三种排序:快排,归并,堆排
Posted Point
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了三种排序:快排,归并,堆排相关的知识,希望对你有一定的参考价值。
转自:http://www.cnblogs.com/LUO77/p/5798149.html
(一)快排
快排考的是最多次的。之前看大神写的算法很简单,思想也很好。就一直用他的思想去思考快排了。挖坑法。
拿走第一个元素作为标兵元素,即挖坑,然后从后面找一个比它小的填坑,然后又形成一个坑,再从前面找一个比标兵大的填坑,又形成一个坑。……最后一个坑填入标兵就好。
然后就是递归了。再在标兵左边排序,右边排序。
1 void QSort(int* num, int start, int end) { 2 if(num == NULL||start >= end) 3 return; 4 int tmp = num[start]; 5 int i = start, j = end; 6 while (i<j) { 7 while (i<j&&num[j]>tmp) { 8 j--; 9 } 10 if (i<j) 11 num[i++] = num[j]; 12 while (i<j&&num[i]<tmp) { 13 i++; 14 } 15 if (i<j) 16 num[j--] = num[i]; 17 } 18 num[i] = tmp; 19 QSort(num, start, i - 1); 20 QSort(num, i + 1, end); 21 }
归并:
归并的思想就是分治-组合。
先divide,然后merge。
divide的思想比较简单,找到middle,再划分A[start,,,,,middle],A[middle+1...end]
对于左边在递归划分,划分直至只剩一个元素,然后再merge。merge的时候需要一个临时数组。merge的时候是A[first...middle]和A[middle+1……end]合并。
对于右边在递归划分,划分直至只剩一个元素,然后再merge。
左边和右边都有序了,然后再将两个数组合并为一个数组。最后整个数组都有序了。(先处理左边,再处理右边)
1 void merge(int* A, int start, int middle, int last, int *tmp) { 2 3 int i1 = start, j1 = middle; 4 int i2 = middle+1, j2 = last; 5 int index = 0; 6 while (i1<=j1&&i2<=j2) { 7 if (A[i1]<=A[i2]) 8 tmp[index++] = A[i1++]; 9 else tmp[index++] = A[i2++]; 10 } 11 while (i1 <= j1) { 12 tmp[index++] = A[i1++]; 13 } 14 while (i2 <= j2) { 15 tmp[index++] = A[i2++]; 16 } 17 for (int i = 0; i<index; i++) { 18 A[start + i] = tmp[i]; 19 } 20 return; 21 } 22 void divide(int* A, int start, int end, int* tmp) { 23 if (start<end) { 24 int middle = (start + end) / 2; 25 divide(A, start, middle, tmp); 26 divide(A, middle+1, end, tmp); 27 merge(A, start, middle, end, tmp); 28 } 29 } 30 void mergesort(int* A, int size) { 31 if (A == NULL || size == 0 || size == 1) 32 return; 33 int* tmp = new int[size]; 34 divide(A, 0, size - 1, tmp); 35 delete[] tmp; 36 return; 37 }
堆排序(以最大堆为例子):
1.首先要构建一个最大堆(从size/2-1位置开始维护堆,叶子节点默认已经是一个最大堆了,维护到根节点,则已经构成一个最大堆)
2.交换根节点(此时根节点是最大值),和最后一个节点,破坏了最大堆的性质,此时继续维护最大堆(维护最大堆的过程就是类似直接插入排序,找到维护点合适插入的位置,保证最大堆性质不被破坏就好)
3.循环交换最后一个节点和根节点,每次维护最大堆的规模减一(找到最大,找到次大,次次大……),到最后到根节点,也就排序完成了。
1 void swap(int& a, int& b) { 2 a ^= b; 3 b ^= a; 4 a ^= b; 5 } 6 void HeapAdjust(int* A, int size, int start) { 7 int i = start; 8 int j = 2 * i + 1; 9 int tmp = A[i]; 10 while (j <= size) { 11 if (j + 1 <= size&&A[j + 1]>A[j]) 12 j++; 13 if (A[j] <= tmp) 14 break; 15 A[i] = A[j]; 16 i = j; 17 j = 2 * i + 1; 18 } 19 A[i] = tmp; 20 return; 21 } 22 23 void CreateHeap(int* A, int size) { 24 for (int i = size / 2 - 1; i >= 0; i--) 25 HeapAdjust(A, size - 1, i); 26 } 27 28 void HeapSort(int* A, int size) { 29 if (A == NULL || size == 0 || size == 1) 30 return; 31 CreateHeap(A, size); 32 for (int i = size - 1; i >= 1;) { 33 swap(A[0], A[i--]); 34 HeapAdjust(A, i, 0); 35 } 36 }
以上是关于三种排序:快排,归并,堆排的主要内容,如果未能解决你的问题,请参考以下文章
七大排序算法(插排,希尔,选择排序,堆排,冒泡,快排,归并)--图文详解
常见排序算法基本原理及实现(快排,归并,堆排,直接插入.....)
常见排序算法基本原理及实现(快排,归并,堆排,直接插入.....)