1、排序:(在c语言中很重要)
排序,字面意思就是按照一定的顺序排列,一般分为两种:
1、从小到大;(升序)
2、从大到小;(降序)c语言中主要介绍四个排序:
1、选择排序;
2、冒泡排序;
3、插入排序;
4、快速排序;
1、选择排序:(先统一写升序排列)
1、依靠算法,算法主要是数学逻辑;所以我们要了解算法思想,掌握c语言如何实现、选择和应用;
2、选择排序基本思想:给合适位置选择合适的数;
思考过程:首先先假设一个最小值,设为min,假设min = a[0],从最开始进行比较,假定数组的长度为len,所以数组对应的下标的最大值为len - 1,从a[0]往后依次比较,因为a【0】作为已经作为比较数,所以他一共可以跟数组的数比较len - 1次,依次比较过程中,如果接下来的数比他小,就进行交换(需要定义一个中间值进行存储),依次比较到数组最后一个数字,然后结束循环,此时a【0】中就会存下比较完过后的最小值,然后就开启下次循环,在下次循环过程中,因为a【0】的值已经确定是最小值,所以需要固定住,于是第二次循环从a【1】开始,并且循环的次数也会少一次;所以用两个循环,小的用来记录进行一次排序的操作,一次可以排出一个数,大的用来控制排序次数,即排好的数的个数;
1、1基本用法举例:
将下列数组按升序排列:
#include<stdio.h> int main(void) { int a[] = {7,5,4,3,6,0,1,2}; // 定义一个数组 int i,j,temp; int len = sizeof(a)/sizeof(a[0]); //求出数组的长度 for(i = 0; i<len-1;i++) //大循环控制循环的次数,i<len-1 证明循环len-1次, { for(j = i;j< len;j++) //小循环来进行单个数的排列,一次大循环过后,小循环里的数排列好一个。 { if( a[i] > a[j] ) //进行判断,一次循环中a[i]的值不动,一直跟变化的a[j]比。 { temp = a[i]; //判断成立就交换位置 a[i] = a[j]; a[j] = temp; } } } for(j = 0; j < len ; j++) //从0 - len-1打印出来 { printf("%d",a[j]); } return 0; }
2、冒泡排序
1、基本过程:类小气泡,一次冒出一个数,相邻两个元素两两比较,小的放前,大的放后;
2、思想:首先,研究数学关系,假设长度为n的一个数组,第一次比较,从a【0】开始,即从第一个数开始,一共比较n-1次,最后一个值就是最大的了,然后结束循环,次数是n-1;第二次依然从a【0】,即第一个数开始,由于最后一个数已经固定,所以次数会再少一次,为n--1-1,然后结束循环;第三次依然从a【0】开始,由于后面两个数已经有顺序,固定了,所以循环顺序又少一次,即为n -1 -1 -1;……,由于排第一次的规律已经出现,所以只需要再套一个循环然后控制循环次数就好,外循环为len-1次。循环到a【len-1-1】。
3、基本流程图解:
2.1基本用法举例:
定义一个数组,用冒泡法实现升序排列:
#include<stdio.h> int main(void) { int a[] = {8,7,6,5,4,3,2,1}; //定义数组 int i,j,temp; int len = sizeof(a) / sizeof(a[0]); //求出数组长度 for(i = 0; i < len - 1 ;i++) // 控制循环次数 { for(j = 0; j< len - i - 1 ; j++ ) { if(a[j] > a[j+1]) // 前面的数比后面的数大,所以交换 { temp = a[j+1]; a[j+1] = a[j]; a[j] = temp; } } } for(j=0;j<len;j++) //打印 { printf("%d",a[j]); } return 0; }
3、插入排序:
1、例子:军训,行列,一个人,不排序,加入一个人,排序;
2、思想:在有序序列中,找到合适的位置插入;
过程:为了方便理解,以两个数组为例,首先准备两个数组,分别为a【i】,a【j】;从a中取出a【0】 = b【0】;第一个数不用判断,直接令a【0】=b【0】,放进去就行,此时i=j;第二个数a【1】,预备存进b【1】,但是需要跟b数组中的b【0】比大小,如果比b【0】大,直接存,如果比b【0】还小,需要存进b【0】的位置,所以先取出a【1】,存进一个中间量t中,先不放进b数组中,t = a【1】,判断完后,若t<b【0】,所以,令b【1】=b【0】;b【1】中放更大的值,即b【0】,此时b【0】=t,b【0】中存放a【1】;注意因为越往后需要判断的次数越多,每次都要往前比,决定需要放的位置,确定位置后才会停止,所以需要多次判断循环,循环结束的条件就是:比较到j = 0的位置,即为底部b【0】,或者是判断结束,t > b【j-1】,要放的数比前一个数大了,不需要比较了,循环结束。所以用while语句,while(j>0 && t< b【j -1】),这个时候循环继续,循环内语句应该为:b【j】=b【j-1】;--j(每次需要往前比,--j是使循环趋于结束的条件,也是循环动起来的条件,因为每次都需要往前比,j的数在减小)意思就是如果要放进的数据比前一个数据小,就把前一个数据挪到前面去,不用担心覆盖问题,因为j = i,并且t = a【i】,数据是已经存在t中,b【j】的位置相当于空的,随便放数据。挪空位就行;
进阶:在a数组上直接操作:原地插入,与非原地插入代码差距不大,就是把b改成a,再将输出改为a【j】输出;
3.1基本应用举例:
定义一个数组,用插入排序方法实现升序排列:
#include<stdio.h> int main() { int a[] = {3,6,5,7,8}; int len = sizeof(a)/sizeof(a[0]); int b[len]; int t,i,j; i = len ; for(i=1;i<len;i++) // 控制循环次数 { t = a[i]; j=i ; while(j > 0 && t < a[j-1]) //排序一次的循环的条件 { a[j] = a[j-1]; // 循环体语句 --j; //使循环趋于结束的操作,也是使循环动起来的操作 } a[j] = t; //比较完后,a[i]给a[j] } for(j = 0;j<len;j++) { printf("%d",a[j]); } return 0 ; }
4、二分查找:(折半查找)
1、大前提:数据需要有序;
2、思想:找到中间位置的数,在数组里面用下标表示,拿这个数和要找的数进行比较;记下mid为中间值,begin和end为起始位置和结束位置,定义mid = (begin + end)/2
4.1基本用法举例:
打印出6在数组中所在的位置:
#include<stdio.h> int main(void) { int a[8] = {1,2,3,4,5,6,7,8}; int begin,end,mid; int b = 6; begin = 0; end = 7; while(begin<=end) { mid =(begin+end)/2; if(a[mid] >b ) { end = mid - 1; }else if(a[mid]<b) { begin = mid +1; }else break; } if(end > begin) { printf("a[%d]",mid); }else printf("error\n"); return 0; }