说明:在C/C++中常见的排序方法有两种,第一种为选择排序法,第二种为冒泡排序法,本文将对这两种排序法进行优化,并给出一种更为快捷的排序法。
一.未优化的排序法
现在假如要对一个数组进行排序,假设这个数组为int arr[10],则对该数组元素进行排序常见有两种方法:
1.选择排序法
1 void sortlist1(int *arr,int n) 2 { 3 for(int i = 0;i < n-1;i++) 4 { 5 for(int j = i+1;j < n;j++) 6 { 7 if(arr[i] > arr[j]) 8 { 9 arr[i] ^= arr[j]; 10 arr[j] ^= arr[i]; 11 arr[i] ^= arr[j]; 12 } 13 } 14 } 15 }
其中arr为待排序的数组名,n为数组中所含的元素个数,内重循环中 arr[i] > arr[j] 决定了排序方式为从小到大;反之则为从大到小。
2.冒泡排序法
1 void sortlist2(int *arr,int n) 2 { 3 for(int i = 0;i < n-1;i++) 4 { 5 for(int j = 0;j < n-1-i;j++) 6 { 7 if(arr[j] > arr[j+1]) 8 { 9 arr[j] ^= arr[j+1]; 10 arr[j+1] ^= arr[j]; 11 arr[j] ^= arr[j+1]; 12 } 13 } 14 } 15 }
其中arr为待排序的数组名,n为数组中所含的元素个数,内重循环中 arr[i] > arr[j] 决定了排序方式为从小到大;反之则为从大到小。
二.优化前两种排序方法
1.选择排序法的优化(以从小到大的排列顺序为例)
从上面的代码可知,选择排序法的思想是让第 i(i 从0开始) 个元素分别与其后面的每个元素进行比较,当比较结果为大于时,就进行交换,这样比较一轮下来,第i个元素成了此轮比较中的最小元素,再继续比较完所有轮,就实现了数组从小到大的排列。这样的排列使得选择排序法的交换次数过于多,降低了排序效率。所以,对选择排序法的优化方案就是:比而不换,记录下标!
1 void sortlist(int *p,int n) 2 { 3 for(int i = 0;i<n;i++) 4 { 5 int idx = i; 6 for(int j = i+1;j<n;j++) 7 { 8 if(p[idx] > p[j]) 9 idx = j; 10 } 11 if(idx != i) 12 { 13 p[idx] ^= p[i]; 14 p[i] ^= p[idx]; 15 p[idx] ^= p[i]; 16 } 17 } 18 }
如上代码,每次内重循环之后,idx记录本次循环中比较的最小值或最大值(此处为最小值),若idx != i,则说明 i 并不是这次比较的最大或最小值,则进行交换,结束本次循环。
2.冒泡排序法优化(以从小到大为例)
冒泡排序法的思想是每轮用第 j(j从0开始) 个元素与第 j+1个元素进行比较,如果大于则交换;这样一轮下来,最大的元素就像冒泡一样到了最后,这样继续比较完所有轮,就实现了冒泡从小到大排序。由此可见,对于冒泡排序法,当某一轮中没有发生过元素的交换时,则表明整个元素序列已经有序了,从而不需要在比较下去。因此,冒泡排序的优化方案为:序而不排。
1 void sortlist2(int *p,int n) 2 { 3 for(int i = 0;i<n;i++) 4 { 5 int flag = 0; 6 for(int j = 0;j<n-1-i;j++) 7 { 8 9 if(p[j] > p[j+1]) 10 { 11 p[j] ^= p[j+1]; 12 p[j+1] ^= p[j]; 13 p[j] ^= p[j+1]; 14 flag = 1; 15 } 16 } 17 if(flag == 0) 18 break; 19 } 20 }
如果在一个内循环之内,都为有序排列,即没发生过交换事件,则标志flag为0,直接退出循环。
三.递归排序法
排序思想:对一组元素,选取第一个元素为比较基数,然后其他元素与他进行比较,比它大的放右边,比它小的放左边,一轮完成,该元素左边都是比它自身小的,右边都是比它大的;然后分别对刚才基数左边和右边的元素重复上述操作,直至排序完成。
1 void sortlist3(int *p,int low,int high) 2 { 3 if(low < high) 4 //判断元素是否大于1,至少2个元素才排序 5 int l = low; 6 int h = high; 7 int middle = p[low ]; 8 //此处只能用p[low],不能用p[0],因为后面递归要用到 9 while(l < h) 10 { 11 while(p[h] >= middle && l<h) 12 h--; 13 p[l] = p[h]; 14 while(p[l] <= middle && l<h) 15 l++; 16 p[h] = p[l]; 17 } 18 p[h] = middle; 19 sortlist3(p,low,h-1); 20 sortlist3(p,h+1,high); 21 } 22 }
其中 p 为数组名,low为数组起始地址 0,high 为数组的元素个数减1。