这几天看了郝斌的数据结构视频,对于各种排序方式有了更深刻的理解。下面与大家分享下我的学习成果,不足之处忘指正。
PS:博文中的代码都是自己敲的,便于理解。
这里讲的五种排序方式,是指冒泡排序、直接选择排序、直接插入排序、快速排序以及二路归并排序。
冒泡排序:排序的思路正如“冒泡”二字,每次比较第i和i+1个位置的值,若a[i]>a[i+1],则交换。这样第一趟下来,最大的数在第n-1个位置;第二趟下来,次最大的数在第n-2个位置,依此类推,直到所有的数排序完毕。
C语言的代码为(p指向数组首元素,len表示数组元素的个数):
void bubbleSort(int *p, int len) { int i = 0; int j = 0; int temp = 0; for (i = 0; i < len-1; i++) { for (j = 0; j < len-1-i; j++) { if (p[j] > p[j+1]) { temp = p[j]; p[j] = p[j+1]; p[j+1] = temp; } } } }
冒泡排序是稳定的,平均时间复杂度为o(n2)
直接选择排序。若是从小到大排序,则第1趟把最小的值放在第0个位置,第2趟把次最小值放在第1个位置,依此类推,直到所有的数排序完毕。
c语言代码为:
void selectSort(int *p, int len) { int i = 0; int j = 0; int temp = 0; for (i = 0; i < len; i++) { for (j = i+1; j < len; j++) { if (p[j] < p[i]) { temp = p[i]; p[i] = p[j]; p[j] = temp; } } } }
直接选择排序是不稳定的算法,平均时间复杂度也是o(n2)。看到网上很有人认为选择排序是稳定的算法,其实不然,例如5,3,5,2,1。第一趟排序完后,第一个5与最后的1交换,位置为2的5自然在原本位置为0的5的前面了。
直接插入排序。假定前i个数已经有序,直接插入排序是把第i+1个数插入到前i个数中的合适位置,重新组成大小为i+1个数的有序序列。
C语言实现代码:
void insertSort(int *p,int len) { int i = 0; int j = 0; int temp = 0; for (i = 1; i < len; i++) { temp=p[i]; for (j = i; j > 0 && temp < p[j-1]; j--) { p[j] = p[j-1]; } p[j] = temp; } return; }
直接插入排序是稳定的,平均时间复杂度也是o(n2)。
快速排序。快速排序采用递归思想,速度自然快很多。假定有n个数,参考值value,也就是我们的比较对象为数组的第一个元素,那么一趟快速排序后,value左侧的值都比value小,右侧的值都比value大。然后再按此方法对这两部分数据分别进行快速排序,依此类推,直到整个数据变成有序序列。
C语言代码如下:
void quickSort(int *p,int low ,int high) { int posi = 0; if (high > low) { posi = findPosi(p,low,high); if (posi > low){ quickSort(p,low,posi-1); } if (posi < high){ quickSort(p,posi+1,high); } } } int findPosi(int *p,int low,int high) { int value = *(p+low); while (high > low) { while(p[high] >= value && high > low) { high--; } p[low] = p[high]; while (p[low] <= value && low < high) { low ++; } p[high] = p[low]; } p[low] = value; return low; }
快速排序是不稳定的,平均时间复杂度是o(log2n)。
最后是归并排序。二路归并排序的思想是分而治之,即divide and conquer。divide:不断地拆分数组,直到每个数组都只有一个元素。conquer:并,把拆分后的数组按关键字排序,不断合并,直到整个数据有序。很明显,二路归并排序利用了递归的思想。
下面给出它的C语言实现:
void divide(int *p,int low,int high){ int mid = (low + high)/2; if (low < high){ divide(p,low,mid); divide(p,mid+1,high); } GuiBingSort(p,low,mid,high); } void GuiBingSort(int *p,int low,int mid, int high){ int leftIndex = low; int rightIndex = mid+1; int tempIndex = 0; int tempLen = high-low+1; int *temp = (int *)malloc(sizeof(int)*(tempLen)); if (NULL == temp){ printf("分配内存失败!\n"); return; } while(leftIndex <= mid && rightIndex <= high){ if (p[leftIndex] <= p[rightIndex]){ temp[tempIndex] = p[leftIndex]; leftIndex++; }else{ temp[tempIndex] = p[rightIndex]; rightIndex++; } tempIndex++; } if (leftIndex > mid){ while(rightIndex <= high){ temp[tempIndex] = p[rightIndex]; rightIndex++; tempIndex++; } }else if (rightIndex > high){ while (leftIndex <= mid){ temp[tempIndex] = p[leftIndex]; leftIndex++; tempIndex++; } } int i = 0; for (i = 0; i < tempLen; i++ ){ p[i+low] = temp[i]; } free(temp); return; }
归并排序是稳定的,平均时间复杂度是o(log2n)。
最后附上main函数的代码:
int main() { int a[7] = {1,5,4,89,23,100,-3}; int len = sizeof(a)/sizeof(int); // printf("插入排序之后\n"); //insertSort(a,len); showArray(a,len); // printf("选择排序之后\n"); // selectSort(a,len); showArray(a,len); // printf("冒泡排序之后:\n"); //bubbleSort(a,len); showArray(a,len); // printf("快速排序之后\n"); // quickSort(a,0,len-1); showArray(a,len); printf("归并排序之后\n"); divide(a,0,len-1); showArray(a,len); return 0; }