初学排序时,也比较模糊,多是照猫画虎,不能透彻理解。今天对几种简单的排序的做一小结。日后继续学习、总结更多地、性能更优的排序!
一、选择排序
先把代码贴上
1 #include<stdio.h> 2 int main() 3 { 4 int a[9] = {5,7,4,6,1,9,3,2,8}; 5 int len = sizeof(a)/sizeof(int); 6 int i,j,min,temp,m; 7 for(i = 0; i < len; i++) 8 { 9 min = i; 10 for(j = i+1; j < len; j++) 11 { 12 if(a[min] > a[j]) 13 { 14 min = j; 15 } 16 } 17 18 if(min != i) 19 { 20 temp = a[min]; 21 a[min] = a[i]; 22 a[i] = temp; 23 } 24 } 25 26 for(m = 0; m <len; m++) 27 { 28 printf("%d ",a[m]); 29 } 30 31 return 0; 32 33 }
此处以升序为例
如下图所示,对该数组进行升序排序
选择排序的原理其实很简单,就是用一个变量min始终保存当前未排序序列的最小元素下标。当外层的第一次循环结束后,比较一下参加该次循环的下标是否和当前的min一致,如果一致,则不管,如果不一致交换两个下标对应元素的位置。
下面针对这段话结合上图做一分析:
第一趟:在比较之前,先定义min用来保存当前最小元素的下标。
a[min]分别和a[i+1](a[j])比较,第一次a[0](5)和a[1](7)比较,a[0]小,继续,j++,接着a[0]和a[2]比较,a[0]大,则把当前j值的赋给min,即min = 2; 因为min保存的是当前最小元素下标,现在发现有人比他小了,就要更新自身的值了。那么现在就是用a[2]和a[3]比较了,a[2]小,继续j++。a[2]和a[4]比,a[4]小。更新min的值为4,j++。继续用a[4]和a[5]比,a[4]小,j++。一直比较a[8],发现都是a[4]小,则第一趟比较结束。得出最小元素的下标为4。
然后用外层第一次进入循环的i值和min比较,如果不相等,说明这个i对应的元素不是最小元素,那么就和min下标对应的元素互换位置,将最小元素置于数组首位了。
第二趟:此时的i等于2了,min也重新被初始为2,继续让a[min]和a[i+1]比较,步骤和第一趟的完全相同,这趟下来,又可以找到最小元素的角标。
接下来就是重复这个步骤了。
具体过程如下图:
二、直接插入排序
先贴代码
1 #include<stdio.h> 2 int main() 3 { 4 int a[5] = {5,7,4,6,3}; 5 int len = sizeof(a)/sizeof(int); 6 int i,j,temp,m; 7 for(i = 1; i < len; i++) 8 { 9 if(a[i] < a[i-1]) 10 { 11 temp = a[i]; 12 13 for(j = i-1; j >= 0 && a[j] > temp; j--) 14 { 15 a[j+1] = a[j]; 16 } 17 a[j+1] = temp; 18 } 19 } 20 for(m = 0; m < len; m++) 21 { 22 printf("%d ",a[m]); 23 } 24 return 0; 25 }
话都在图里了:
三、冒泡排序
贴代码:
1 #include<stdio.h> 2 int main() 3 { 4 int a[5] = {5,6,3,7,4}; 5 int i,j,k,temp; 6 int len = sizeof(a)/sizeof(int); 7 8 for(i = 0; i < len - 1; i++) 9 { 10 bool flag = true; 11 for(j = 0; j < len - i - 1; j++) 12 { 13 if(a[j] > a[j+1]) 14 { 15 temp = a[j]; 16 a[j] = a[j+1]; 17 a[j+1] = temp; 18 flag = false; 19 } 20 21 } 22 if(flag) 23 { 24 break; 25 } 26 } 27 28 for(k = 0; k < len; k++) 29 { 30 printf("%d ",a[k]); 31 } 32 return 0; 33 }
上图:
如图所示,针对数组元素为5,6,3,7,4进行了冒泡排序,每次比较相邻的两个元素,若前者大于后者,则互换,反之,不换,继续往后推进。但可以发现,在进行完三次冒泡之后,已经产生了最终结果:3,4,5,6,7。但程序并不会因此停止,它仍会继续执行两轮,进行最后两次的冒泡,但这是没有意义的。所以在代码中增加了标志flag的设定,如果没有比较了,就不再执行操作,就可以认为,当前序已按照要求序列排列完毕!
总结:
简单选择排序:
基本思想为每一趟从待排序的数据元素中选择最小(或最大)的一个元素作为数组首元素,直到所有元素排完为止,简单选择排序是不稳定排序。时间复杂度为O(n2)。
直接插入排序:
基本思想为每一步将一个待排序的记录,插入到前面已经排好序的有序序列中,直到插完所有元素为止。时间复杂度为O(n2)。
冒泡排序:
基本思想为对相邻的元素进行两两比较,顺序相反则进行交换,这样,每一趟会将最小或最大的元素“浮”到顶端,最终达到完全有序。时间复杂度依然为O(n2)