C语言学习笔记分享之数组(冒泡排序)
2015-10-01 16:24
344 查看
//------------------整型变量修饰符 修饰符(int short long long long signed unsigned) 所有修饰符都是用来修整形 int 4 short %hd 2 long %ld 8 long long 8(32位) 用来改变一个整形变量的存数空间 用来改变整形变量的符号 signed 表示是有符号的(默认的就是有符号数) unsigned 表示是一个无符号的数 (正数的取值范围会扩大一倍) %u //--------------------char类型数据存储 存储原理 char a='a' ----->取出'a'的ASCII码值,97,然后转换2进制,存储在一个字节中 注意事项 1)当把一个字符赋值给一个char类型变量,那么系统首先查这个字符所对应的ASCII码,然后把 这个ASCII值放到变量中 2)根据变量中存储的ASCII值,去查ASCII表中对应字符,然后把这个字符打印控制台上,整形和 字符型可以互相转换。 3)char z = '我'; char字节,一个中文字符占3字节(unicode表),所有char不可以存储中文 4)不支持多个字符,多个字符是字符串 char two = 'ac'; printf("%c\n",two); //------------------1)输入一个小写字母,要求转换成大写输出 A 65 a 97 差了32 //------------------数组的基本概念及分类 把具有 相同类型 的若干 变量 按 有序 的形式组织起来。这些按序排列的 同类数据元素 的集合 称为 数组 在C语言中,数组属于构造数据类型。一个数组可以分解为多个数组元素,这些数组元素可以是基本数据类型或是构造类型。 数组的几个名词 1)数组:一组具有相同数据类型的数据的有序的集合 2)数组元素:构成数组的数据。数组中的每一个数组元素具有相同的名称,不同的下标,可以作 为单个变量使用,所以也称为下标变量。 3)数组的下标:是数组元素的位置的一个索引或指示。 4)数组的维数:数组元素下标的个数。根据数组的维数可以将数组分为一维、二维、三维、多维 数组。 存储 按 类型不同划分 数值数组 字符数组 指针数组 结构数组 按维度分类 //----------------------一维数组 如果一个数组的所有元素都不是数组,那么该数组称为一维数组 定义 类型说明符 数组名[常量表达式]; //---------------------注意点 1) 数组的类型实际上是指数组元素的取值类型。对于同一个数组,其所有元素的数据类型都是相 同的。第一个数组元素的地址是数组所占内存块的首地址 2) 数组名的书写规则应符合标识符的书写规定。 命名规则: 1、只能由字母、数字、下划线组成 2、不能数字开头 3、不能与关键字重名 4、严格区分大小写 命名规范: 1、起一个有意义名字 2、驼峰标示 3) 数组名不能与其它变量名相同。 //注意点 4) 方括号中常量表达式表示数组元素的个数,如a[5]表示数组a有5个元素。但是其下标从0开始 计算。 5) 不能在方括号中用变量来表示元素的个数,但是可以是符号常数或常量表达式。 c99不支持使用变量作为元素个数 6) 允许在同一个类型说明中,说明多个数组和多个变量。 //--------------------数组的初始化 类型说明符 数组名[常量表达式] = { 值, 值......值 }; 其中在{ }中的各数据值即为各元素的初值,各值之间用逗号间隔。 //--------------数组初始化的注意事项 1)指定元素的个数的同时,对所有的元素进行显式的初始化 int nums[5] = {1,2,3,4,5}; 2)指定数组的元素个数,对数组进行部分显式初始化 定义的同时对数组进行初始化,没有显式初始化的元素, 那么系统会自动将其初始化为0 int num[5] = {1} ---> 1,0,0,0,0 3)不指定元素个数,定义的同时初始化,它是根据大括号中的元素的个数来确定数组的元素 个数 int nums[] = {1,2,3,5,6}; 4)指定元素个数,同时给指定元素进行初始化 int nums[5] = {[4] = 3,[1] = 2}; 给数组赋值的方法除了用赋值语句对数组元素逐个赋值外 还可采用初始化赋值和动态赋值的方法 使用变量定义的数组不可以定义数组的同时对数组进行初始化 int a = 6; int nums[a]; 先定义后初始化 数组没有初始化,数组里面是垃圾数 数组如果部分初始化,剩下的会自动初始化为0,所以是0 先定义后初始化,后初始化的只会对部分元素初始化,其余依旧是垃圾数 int a[10]; a[1] = 10; a[5]? //垃圾数 //------------------------------数组的引用 数组名[下标] 数组元素通常也称为下标变量。必须先定义数组,才能使用下标变量。 int a[3] = {1,2,3}; a[0] = 1; a[1] = 2; a[2] = 3; a[3]? 正序输出 for (int i=0; i<10; i++) { printf("%d\t",a[i]); } 逆序输出 for (int j=9; j>=0; j--) { printf("%d\t",a[j]); } 数组的遍历 ---> 初始化 for (int i=0;i<len; i++) { printf("请输入数组的第%d个值\n",i+1); scanf("%d",&a[i]); } 数组长度 定义数组 遍历 //----------------------------一维数组的存储方式 存储方式: 1)计算机会给数组分配一块连续的存储空间 2)数组名代表数组的首地址 从首地址位置,依次存入数组的第1个、第2个....、第n个元素 3)每个元素占用相同的字节数(取决于数组类型) 4)并且数组中元素之间的地址是连续。 一维数组的地址 在内存中,内存从大到小进行寻址,为数组分配了存储空间后,数组的元素自然的从上往下排列 存储,整个数组的地址为首元素的地址。 2)数组名存放的是数组的首地址 数组的首地址:数组的第一个元素首地址(第一个元素的第一个字节地址) //-----------------------------计算数组长度 :sizeof(数组名) --> 总字节数 数组的长度 = 数组占用的总字节数 / 数组元素占用的字节数 //-----------------------------数组的越界问题 总结: 一个长度为n的数组,最大下标为n-1, 下标范围:0~n-1 1、约错了对象(访问自己不该访问存储空间) 2、程序崩溃 //-------------------------找最大值 定义变量 遍历存入数组 假设max = a[0] 比较 if(a[i]>max) max=a[i]; //-------------------------数组元素作为函数参数 数组用作函数参数有两种形式: 一种是把数组元素(下标变量)作为实参使用; 一种是把数组名作为函数的形参和实参 数组元素作函数实参,就是把数组元素的值传送给形参 数组名作为函数参数,就是把数组的地址传递过去 1)用数组名作函数参数时,则要求形参和相对应的实参都必须是类型相同的数组 2)在C语言中,数组名除作为变量的标识符之外,数组名还代表了该数组在内存中的起始地址, 因此,当数组名作函数参数时,实参与形参之间不是"值传递",而是"地址传递",实参数组名将 该数组的起始地址传递给形参数组,两个数组共享一段内存单元,编译系统不再为形参数组分配存储单元。 3) 在变量作函数参数时,所进行的值传送是单向的。即只能从实参传向形参,不能从形参传回实 参。形参的初值和实参相同,而形参的值发生改变后,实参并不变化,两者的终值是不同的。 注意点 1形参数组和实参数组的类型必须一致,否则将引起错误。 2形参数组和实参数组的长度可以不相同 3在函数形参表中,允许不给出形参数组的长度,或用一个变量来表示数组元素的个数。 4多维数组也可以作为函数的参数。在函数定义时对形参数组可以指定每一维的长度,也可省去 第一维的长度。 sizeof(地址) --> 地址都是占8个字节 //------------------冒泡排序 int a[5] = {1,7,5,3,2}; 大数下沉,小数上浮 1)比较相邻的元素。如果第一个比第二个大,就交换他们两个。 2)对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。 在这一点,最后的元素应该会是最大的数。 3)针对所有的元素重复以上的步骤,除了最后一个。 4)持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。 for (int i=0; i<len-1; i++) //每趟排序都会确定一个数,所以需要再循环len-i次,但因为每次都是 //相邻的两个数进行比较,为了a[j+1]不越界,让j循环到len-i-1时停止。 for (int j=0; j<len-i-1; j++) { //------------------冒泡排序 外层 len - 1 里层 j < len - i - 1 大数下沉 1)比较相邻的元素。如果第一个比第二个大,就交换他们两个。 2)对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。 在这一点,最后的元素应该会是最大的数。 3)针对所有的元素重复以上的步骤,除了最后一个。 4)持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。 for (int i=0; i<len-1; i++) //每趟排序都会确定一个数,所以需要再循环len-i次,但因为每次都是 //相邻的两个数进行比较,为了a[j+1]不越界,让j循环到len-i-1时停止。 for (int j=0; j<len-i-1; j++) { //若arr[j]>arr[j+1] 若前一位比后一位元素大,则交换顺序 if (arr[j]>arr[j+1]) { int temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } //------------------选择排序思想 外层 len-1 里层 j=i+1 j<len int a[10]={23,12,4,67,20,100,21,45,3,28}; 假设a[0]为最小,分别与a[1] a[2] ... 比较, 在比较过程中,如果有元素的值比a[0]小,交换值 第一种方法 //每一趟都是拿着一个元素与后面其他元素进行比较,找出最小值 void selectSort1(int array[],int len){ // 1、确定需排序趟数 for (int i = 0 ; i < len - 1; i++) { // 2、每一趟怎么处理 for (int j = i + 1; j < len; j++) { if (array[i] > array[j]) { int temp = array[i]; array[i] = array[j]; array[j] = temp; } } } } 第二种方法 void selectSort2(int arr[],int len){ int temp; int min; for (int i=0; i<len - 1; i++) { //每次假设第arr[i]是最小值 min = i; min = i; for (int j=i+1; j<len; j++) { //找到最小的那个元素的下标 if (arr[j]<arr[min]) min=j; } //如果没有找到比arr[i]小的,就不用交换 if(i!= min){ //将第i个元素和最小的元素交换 temp=arr[i]; temp = arr[i]; arr[i]=arr[min]; arr[min] = temp; } } //打印数组 for (int i=0; i<len; i++) { printf("%d\t",arr[i]); } } //----- 冒泡: 外层for (int i=0; i<len-1; i++) 内层for (int j=0; j<len-i-1; j++) //----- 选择排序: 外层for (int i=0; i<len - 1; i++) 内层for (int j=i+1; j<len; j++) //------------------折半查找思想 思路: 先划分空间,再在其空间查找,取中间点,中间点往左,元素的值一定比中间值小,右边的值一定比中间值大. 判断 关键点 if (key>arr[mid]) {low = mid+1;} //右半区查找 if (key<arr[mid]){high = mid - 1;} //左半区查找 找 12 low high 0 1 2 3 4 5 6 7 8 9 // 3 4 12 20 21 23 28 45 67 100 -------------------------------------------- 1 low mid high 2 low mid high 3 low high mid = (low + high) / 2 = 4; a[4] = 21 > 12 --> high = mid - 1 ---> 4 - 1 = 3 mid = (low + high)/2 = 1; a[1] = 4 < 12 --> low = mid + 1 --> 1+1 = 2 mid = (2+3)/2 --> 2 a[2] = 12 == 12 //折半查找 int searchItem(int arr[],int len,int key){ //先要定义变量 int low=0,high=len-1,mid; //循环 while (low<=high) { // 计算 mid的位置 mid = (low+high)/2; printf("mid = %d",mid); // 判断 key a[mid],右半区查找 if (key>arr[mid]) { // key > a[mid] low = mid +1; low = mid+1; }else if (key<arr[mid]){ // key < a[mid] high = mid -1; high = mid - 1; }else{ // key == a[mid] //return mid; return mid; } } // 下面是查找不到的情况 return -1; } //折半插入 不建议看 int insertItemLoc(int arr[],int len,int key){ //先要定义变量 int low=0,high=len-1,mid; //循环 while (low<=high) { // 计算 mid的位置 mid = (low+high)/2; // 判断 key a[mid],右半区查找 if (key>arr[mid]) { // key > a[mid] low = mid +1; low = mid+1; }else if (key<arr[mid]){ // key < a[mid] high = mid -1; high = mid - 1; }else{ // key == a[mid] //return mid; return mid + 1; } } // 下面是查找不到的情况 return low; } //---------------------二维数组 回顾://----------------------一维数组 如果一个数组的所有元素都不是数组,那么该数组称为一维数组 二维数组定义的一般形式是: 类型说明符 数组名[常量表达式1][常量表达式2] 二维数组定义注意事项: 1)数组名严格遵守标识符命名规范 2)二维数组名不能和变量同名 int a; int a[2][3]; 3)数组长度可以是常量,也可以是常量表达式 int a[2+1][3+3]; //相当于定义了int a[3][5]; 4)二维数组长度可以是宏定义 5)xcode编译器支持,C99标准不允许的写法 int x=3,y=4; int a[x][y]; //相当于定义了int a[3][4]; 6) 只定义不初始化,不可以省略长度 int arr[2][3] = {1,2,3, ---> {{第一行元素(一维数组)} 4,5,6} 第二行元素(一维数组)}} 2行3列 /* | a[0] a[1] a[2] 第二维 ----------------------- a[0] | 1 2 3 a[1] | 4 5 6 第一维 */ //--------------------二维数组初始化 二维数组可: 1)按行分段赋值 2)也可按行连续赋值。 1、定义同时初始化 2、先定义后初始化 数组名[行][列] int a[5][6]; 部分初始化,其余自动初始化为0 二维数组可以看作是由一维数组的嵌套而构成的。 二维数组初始化,不能省略第二维 int a[4][3] = {{1,2,3},{4,5,6},{7,8,9},{10,11,12}}; /* | a[0] a[1] a[2] 第二维 ----------------------- a[0] | 1 2 3 a[1] | 4 5 6 a[2] | 7 8 9 a[3] | 10 11 12 第一维 */ //--------------------二维数组遍历 二维数组的元素也称为双下标变量 数组名[第一维下标][第二维下标] 数组名[行][列] for外层循环控制行数 for内层循环控制列数 int score[5][3] = {{80,75,92}, {80,75,92}, {80,75,92}, {80,75,92}, {80,75,92}}; //--------------------二维数组存储 存储方式: 1)计算机会给二维数组分配一块连续的存储空间 2)数组名代表数组的首地址,从首地址位置,依次存入第1行、第2行、..... 3)每一行存储方式,从行首地址还是,依次存储行的第1个元素、第2个元素、第3个元素...... 4)每个元素占用相同的字节数(取决于数组类型) 5)并且数组中元素之间的地址是连续。 arr == &arr[0] == arr[0] == &arr[0][0] arr (数组名 指向第一行元素的地址) &arr[0](第一行元素的地址) arr[0](指向第一行第一个元素的地址) &arr[0][0](第一个元素的地址) int arr[3][4] = {{第一行3个元素(第一行一维数组)}, ----> arr[0] {第二行4个元素(第二行一维数组)}, ----> arr[1] {第三行4个元素(第三行一维数组)}}; ----> arr[2] arr是一个二维数组 总计占用字节数: sizeof(arr); 每行占用字节数: sizeof(arr[0]); 行数: 总字节数/每行字节数 --> sizeof(arr)/sizeof(arr[0]); 列数: 行数/每个类型 --> sizeof(arr[0])/sizeof(int) //应用:求多人多门课平均成绩 //找最大值 //-------------------二维数组做函数参数 1、二维数组元素作为函数参数 二维数组元素作为函数参数,相当于变量的值传递过程。 2、二维数组名作为函数参数 二维数组名作为函数参数,相当于地址传递。 1)在被调用函数中对形参数组定义时可以指定所有维数的大小,也可以省略第一维的大小说明, 如: void Func(int array[3][10]); void Func(int array[][10]); 注意: 二者都是合法而且等价,但是不能把第二维或者更高维的大小省略, 不合法的: void Func(int array[][]); void Func(int array[3][]); 一定不能省略第二维 2)实参数组维数可以大于形参数组 形参数组只取实参数组的一部分,其余部分不起作用。 3)类型长度要一致 //---------------------从键盘接收数据构成二维数组 输出 void printArray(int m,int n,int a[m] ){ for (int i = 0; i<m; i++) { for (int j=0; j<n; j++) { printf("%d\t",a[i][j]); } printf("\n"); } } 输入 void initArray(int m,int n,int a[m] ){ for (int i=0; i<m; i++) { for (int j=0; j<n; j++) { printf("请输入第%d行第%d列元素赋值\n",i,j); scanf("%d",&a[i][j]); } } } //---------------------《迷宫》 /* | a[0] a[1] a[2] 第二维 ----------------------- a[0] | 1 2 3 a[1] | 4 5 6 a[2] | 7 8 9 a[3] | 10 11 12 第一维 ###### #O## # ## # # # # ## # ###### */ 判断下一个位置是否是路,是路就让这两个值交换 假设往下走 //核心要知道小人的下一个位置是否是路 if (map[currentX-1][currentY]==street) { //让小人开始移动,移动的核心:小人和路交换 char temp; // map[currentX][currentY]; 小人当前位置 // map[currentX-1][currentY];小人的下一个位置 temp = map[currentX][currentY]; map[currentX][currentY] = map[currentX-1][currentY]; map[currentX-1][currentY] = temp; //重新记录小人的当前位置 currentX--; } |
相关文章推荐
- 在C++中,为了让某个类只能通过new来创建实例(即如果直接创建对象,编译器将报错),怎样做?
- stitching.cpp鱼眼图像拼接融合 源码分析
- c语言入门经典(第5版)
- C语言单向动态链表程序,实现链表的建立,合并,重新排序,链表元素的插入与删除,以及根据元素成员的值进行元素删除。
- C++容器(三):pair类型
- C++容器(三):pair类型
- C++primer:string流
- C++中的Static关键字
- 黑马程序员---C语言学习笔记之预处理指令、宏和条件编译
- c/c++: uint8_t uint16_t uint32_t uint64_t size_t ssize_t数据类型
- c语言知识点复习
- C++中new和malloc的区别
- 递归求解1~9组成的特殊9位整数
- C++类包含问题(重复包含和相互包含)
- 黑马程序员——OC语言基础---对象和方法
- Java jna学习之----VC++2010创建并调用动态链接库dll
- 截木棍(最大公约数)
- 我的第一个C++程序
- C++ Struct
- 深入理解C++三大特性之一 ——多态