一.数组基础
1.数组定义
数组一般形式:类型说明符 数组名 [常量或常量表达式];
类型说明符:基本数据类型、构造数据类型(不能是void类型)。说明数组中保存的数据的数据类型。数组名:遵循标识符的命名规则。
常量或常量表达式:数组中可以保存的元素的个数。
int a[10];sizeof (a); //40字节
char str[32]; //32字节
float array[5]; //20字节
注意:
1.常量表达式中可以包括常量和符号常量,不能包含变量。也就是说,C语言不允许对数组的大小作动态定义,即数组的大小不依赖于程序运行过程中变量的值。例如,下面这样定义数组是不行的
int n; scanf("%d",&n); //在程序中临时输人数组的大小 int a[n];
2.数组访问
数组必须先定义,然后使用。C语言规定只能逐个引用数组元素而不能一次引用整个数组。
下标可以是整型常量或整型表达式。例如:
a[0]=a[5]+a[7]-a[2* 3]
注意:定义数组时用到的“数组名[常量表达式]”和引用数组元素时用到的“[下标]”的区别,例如:
a[0]=a[5]+a[7]-a[2* 3] int a[10]; //定义数组长度为10 t=a[6]; //引用a数组中序号为6的元素。此时6不代表数组长度数组定义时只能用常量,但访问时可以使用变量访问(应以整型为结果访问)
3.数组初始化
对数组元素的初始化可以用以下方法实现。
(1)在定义数组时对数组元素赋予初值。例如:
int a[10]={0,1,2,3,4,5,6,7,8,9};将数组元素的初值依次放在一对花括号内。
(2)可以只给一部分元素赋值。例如:
int a[10]={0,1,2,3,4};定义a数组有10个元素,但花括号内只提供5个初值,这表示只给前面5个元素赋初值,后5个元素值为0
(3)如果想使一个数组中全部元素值为0,可以写成:
int a[10]= {0,0,0,0,0,0,0,0,0,0};或int a[10]={0}; 不能写成int a[10]={0*10};(4)在对全部数组元素赋初值时,由于数据的个数已经确定,因此可以不指定数组长
int a[5]={1,2,3,4,5};可以写成int a[]={1,2,3,4,5};在第二种写法中,花括号中有5个数,系统就会据此自动定义a数组的长度为5。但若数组长度与提供初值的个数不相同,则数组长度不能省略。例如,想定义数组长度为10,就不能省略数组长度的定义,而必须写成:
int a[10]={1,2,3,4,5};
只初始化前5个元素,后5个元素为0。(5)数组定义时,若int a[],没指定数组大小,则需要初始化;数组定义若不进行初始化,则赋随机值。
4.数组存储
数组的存储形式
单一性:数组中的元素,每个元素的数据类型都是一致。
有序性:数组中的元素按照a[0]-a[n]的顺序进行存储。
连续性:数组在内存中选取连续内存空间存储。数组越界:
1.初始化数组时,初始化的元素个数超出了数组本身的元素个数。
2.访问数组元素时,[]中的下标超出了数组元素的访问范围。注意当使用sizeof时数组越界编译器并不会报错,
sizeof是编译时运算符,它计算的是表达式或类型的字节大小,而不会对表达式进行求值(即不会真正执行该表达式)。因此,即使数组长度为 10,使用sizeof(a[10])也不会报错。
5.数组排序(选择、冒泡、插入排序)
1)选择排序
基本思想是:每一趟(如第i趟)在后面n-i+1(i=1,2,...,n-1)个待排序元素中选取关键字最小的元素,作为有序子序列的第i个元素,直到第n-1趟做完,待排序元素只剩下1个,就不用再选。
简单选择排序不断重复地选择待排序元素中最小的一个元素,当前处于第几轮就将该元素与
第几个位置上的元素交换位置,直至所有元素完成排序。例如,第一轮将最小的元素与第一个位置上(arr[0])的元素交换位置,第二轮将第二小的元素与第二个位置上的元素交换位置,不断重复上述过程,直到所有元素都已有序。具体步骤如下:
(1)从待排序序列中,找到关键字最小的元素;
(2)将该元素与待排序序列中的第一个元素交换位置(初始时,有序序列中没有元素);
(3)对于余下的n-1个元素,重复上述两个步骤。
对于给定的待排序关键字序列(25,20,99,16,11,14,22,25,42,17),使用简单选择排序的过程流程如下图所示:
简单选择排序算法实现代码如下:
for(int i=0;i<len-1;i++) { for(int j=i+1;j<len;j++) { if( arr[i]>arr[j]) { tmp=arr[i]; arr[i]=arr[j]; arr[j]=tmp; } } }也可采用如下方式:其中swap为封装交换两数的函数;
由于采用双重循环,故其时间复杂度为O(n*n);空间复杂度没有额外开销,为O(1);同时该算法不具备稳定性,因为其在内层循环中当遇到两数相同时并不会进行替换,而会继续向后比较,当遇到满足条件的值时会进行替换,从而越过中间相同的数,改变了两数的顺序
2)冒泡排序
基本思想:从后往前(或从前往后)两两比较相邻元素的值,若为逆序(A[i-1]>A[i]),则交换它们,直到序列比较完。我们称它为第一趟冒泡,结果是将最小的元素交换到待排序列的第一个位置(或将最大的元素交换到待排序列的最后一个位置),关键字最小的元素如气泡一般逐渐往上“漂浮”至“水面”(或关键字最大的元素如石头一般下沉至水底)。下一趟冒泡时,前一趟确定的最小元素不再参与比较,每趟冒泡的结果是把序列中的最小元素(或最大元素)放到了序列的最终位置,这样最多做n-1趟冒泡就能把所有元素排好序。
流程图如下所示:
冒泡排序算法实现代码如下:
for(int i=0;i<len-1;i++) { for(int j=0;j<len-i-1;j++) { if( arr[j]>arr[j+1]) { tmp=arr[j]; arr[j]=arr[j+1]; arr[j+1]=tmp; } } }书中相比上述代码额外采用了flag标志位用来判断表初始是否有序,并且倒序实现,每次将最小值交换到序列前方,参考上述流程图。
其性能如下:
3)插入排序
基本思想:假设待排序序列存放在数组arr[0,...,n-1]中(temp代表当前待排序元素),算法步骤如n-1个元素无序。排序过程的插入操作主要分为两部分:
(1)将数组中的数据分成有序和无序两个部分。初始状态下,第1个元素(arr[0])有序,后
(2)循环n-1次,依次将后n-1个元素按关键字有序插入有序序列中的合适位置上。
1有序序列中的元素从后往前地与当前待排序的元素比较,寻找其插入位置p;
2将有序序列中位置p及其之后的元素统一后移1位,然后将当前待插入元素插入目标位置
p。需要注意的是,在算法的实现上,一般是在比较的同时移动数据元素。流程图如下:
插入排序算法实现代码如下:
性能如下:
6.折半查找
折半查找也称二分查找,是一种在有序数组中查找某一特定数据元素的查找算法。
基本思想:
(1)从当前表的中间元素开始查找,如果中间元素刚好是要查找的数据元素,则查找成功(初
始时刻的当前表是整个数组)。
(2)如果要查找的元素大于(或小于)中间元素,则在数组大于(或小于)中间元素的那一半
子表中查找,在子表中从步骤(1)重新查找。
(3)如果在当前数组为空,则代表查找失败。
折半查找算法的每一次比较都使查找范围缩小一半,该算法对于待查找的列表有两个要求:
(1)查找表必须支持随机查找,为此必须采用顺序存储结构;
(2)查找表内元素必须按关键字大小有序排列。流程图如下:
折半查找算法实现代码如下:
int low=0,mid=0,high=len-1; while(low<=high) { mid=(low+high)/2; if(num>arr[mid]) low=mid+1; else if(num<arr[mid]) high=mid-1; else { printf("%d\n",arr[mid]); return 0; } } printf("not find\n");此外,因为折半查找需要方便地定位查找区域,所以它要求线性表必须具有随机存取的特性。因此,该查找法仅适合于顺序存储结构,不适合于链式存储结构,且要求元素按关键字有序排列。
二.字符数组
1.字符型数组定义
char 数组名 [常量];
数组名:标识符命名规则
char str[32];--->sizeof(str)--->32字节
2.字符型数组元素访问
数组名[下标]:
str[0]; ---->char
注意:下标避免数组越界。
3.字符型数组初始化
局部初始化:
char str[32] = {'h', 'e', 'l', 'l', 'o'}; char str[32] = {"hello"}; //字符串初始化 char str[32] = "hello";没有初始化的部分,默认存储0('\0'字符)
全部初始化:
char str[5] ={'h','e','l,'l,'o'}; char str[] = {'h','e','l','l','o'}; ----->5字节 char str[] = {"hello"}; ------>6字节 == char str[] = "hello";
当以字符串初始化时,[]常量被省略时,将来数组空间按照初始化后的字符个数去确定,额外增加‘0'字符的存储位置
4.字符型数组输入输出
输入:
1.scanf
scanf("%s",str); 只能输入不带空格,tab与enter的字符,否则停止2.gets()
输出:
1.以遍历的方式输出
for (i=0;str[i]!='\0';++i) { printf("%c", str[i]); }2.以字符串方式输出
printf("%s\n",str);3.puts输出
puts(str);//自动换行
5.字符型数组相关函数
strlen(str):计算字符串的长度(字符型数组中有效字符个数,不包含'\0')
其一般形式为:
strlen(字符数组)。它是测试字符串长度的函数。函数的值为字符串中的实际长度(不包括'\0'在内)。例如:char str[10]={"China"}; printf("%d",strlen(str));输出结果不是10,也不是6,而是5。
strcpy(str1,str2):字符串拷贝
其一般形式为:strcpy(字符数组1,字符串2)
strcpy是stringcopy(字符串复制)的简写。它是“字符串复制函数”,作用是将字符串2复制到字符数组1中去.
strcat(str1,str2):字符串拼接
其一般形式为:strcat(字符数组1,字符数组2)
strcat是String Catenate(字符串连接)的缩写。其作用是连接两个字符数组中的字符串,把字符串2接到字符串1的后面,结果放在字符数组1中,函数调用后得到一个函数值即字符数组1的地址。
sizeof(str):求字符型数组在内存中所占的字节数(和空间开辟时大小有关)。
char str1[]={"hol"};
printf("%ld\n",strlen(str1)); //3
printf("%ld\n",sizeof(str1)); //4
注意,strlen只能读取以\0为结尾的字符串,若定义char str1[]={'q','t'}此类,则不会输出2,而是
会继续向t后面的内存查找,直到找到以\0为结尾的字符位置;而若定义char str1[]={'q','t','\0'}则会
输出2。
三.二维数组的定义与引用
未完待更......











2245

被折叠的 条评论
为什么被折叠?



