选择排序的基本思想为:每一趟(例如第i趟)在后面的n-i+1(i=1,2,3,…...,n-1)个待排序元素中选取关键字最小的元素,作为有序序列的第i个元素,直到n-1趟做完,待排序元素只剩下一个,就不用选了,序列也排序完毕。选择排序主要有简单选择排序和堆排序,下面分别就这两种排序算法进行讨论。
1.简单选择排序
从上面选择排序的思想中可以很直观的得出简单选择排序的算法思想:假设排序列表为L[1……n],第i趟排序从L[i……n]中选择关键字最小的元素与L(i)交换,每一趟排序可以确定一个元素的最终位置,这样经过n-1排序就可以使得整个列表有序。
具体实现的代码如下:
1 #include<iostream> 2 using namespace std; 3 4 //声明打印辅助函数 5 void printArray(int array[], int length); 6 //声明简单选择排序函数 7 void SimpleSelectSort(int array[], int length); 8 9 int main() 10 { 11 int array[] = { 12, 3, 6, 4, 27, 9 }; 12 int length = sizeof(array) / sizeof(*array); 13 14 cout << "排序前序列为:" << endl; 15 printArray(array, length); 16 17 SimpleSelectSort(array, length); 18 cout << endl << "简单选择排序后序列为:" << endl; 19 printArray(array, length); 20 cout << endl; 21 system("pause"); 22 return 0; 23 } 24 25 void printArray(int array[], int length) 26 { 27 for (int i = 0; i < length; i++) 28 { 29 if (i == length - 1) 30 cout << array[i]; 31 else 32 cout << array[i] << ","; 33 } 34 } 35 36 //简单选择排序函数 37 void SimpleSelectSort(int array[], int length) 38 { 39 for (int i = 0; i < length - 1;i++) 40 { 41 int min = i; 42 for (int j = i + 1; j < length;j++) 43 { 44 if (array[min] > array[j]) 45 { 46 min = j; 47 } 48 } 49 if (min != i) 50 { 51 int tmp = array[min]; 52 array[min] = array[i]; 53 array[i] = tmp; 54 } 55 } 56 }
2.堆排序
堆排序中的几个操作而是解释如下:
(1)建堆
堆排序的关键是建堆,对初始序列建堆,就是一个反复筛选的过程。n个结点的完全二叉树,最后一个结点是n/2个结点的孩子。对n/2个结点为根的子树筛选(对于大根堆:若根结点的关键字小于左右子女中的较大者,则对其进行交换),使该子树成为堆,最后依次对各结点(n/2-1~1)为根的子树进行筛选,看该结点是否大于其左右子结点的值,若不是,则将左右子结点中较大值与之交换,交换后可能破坏下一级的堆,于是继续采用上述方法构造下一级的堆,直到已该结点为根的子树构成堆为止。反复利用上述筛选策略,直到根结点。建议大家动手操作一下,加深理解。
(2)插入:先将新结点放在堆的末端,再对这个新结点执行向上调整操作。
(3)删除:先将堆的最后一个元素和堆顶元素进行交换,此时对根结点进行向下调整操作。
堆排序具体实现代码如下:
1 #include<iostream> 2 using namespace std; 3 4 /************************************************************************/ 5 /* 本文的array中的物理位置与逻辑位置一致,0号位置留出供后序操作使用 */ 6 /************************************************************************/ 7 8 //声明打印辅助函数 9 void printHeapArray(int array[], int length); 10 11 //声明堆排序函数及相关辅助函数 12 //向上调整函数 13 void AdjustUp(int array[], int k); 14 //向下调整函数 15 void AdjustDown(int array[], int k, int length); 16 //建立大根堆函数 17 void BuildMaxHeap(int array[], int length); 18 //堆排序函数 19 void HeapSort(int array[], int length); 20 21 int main() 22 { 23 int array[] = { 0, 12, 3, 6, 4, 27, 9 }; 24 int length = sizeof(array) / sizeof(*array) - 1; 25 cout << "排序前序列为:" << endl; 26 printHeapArray(array, length); 27 28 HeapSort(array, length); 29 cout << endl << "堆排序后序列为:" << endl; 30 printHeapArray(array, length); 31 cout << endl; 32 system("pause"); 33 return 0; 34 } 35 36 void printHeapArray(int array[], int length) 37 { 38 for (int i = 1; i <= length; i++) 39 { 40 if (i == length ) 41 cout << array[i]; 42 else 43 cout << array[i] << ","; 44 } 45 } 46 47 //向上调整函数 48 void AdjustUp(int array[], int k) 49 { 50 //k为向上调整的结点,在这里也是堆的元素个数 51 //1.array[0]存储带调整结点 52 array[0] = array[k]; 53 int i = k / 2; 54 while ((i > 0) && (array[i] < array[0])) 55 { 56 //2.开始交换元素 57 array[k] = array[i]; 58 k = i; 59 i = k / 2; 60 } 61 //3.完成元素交换 62 array[k] = array[0]; 63 } 64 65 //向下调整函数,用于插入元素 66 void AdjustDown(int array[], int k, int length) 67 { 68 array[0] = array[k]; 69 for (int i = 2 * k; i <= length; i = i * 2) 70 { 71 //取k的孩子结点中key较大的元素,特别需要注意的是 72 //这里if语句中一定要有i<length的判断,因为若i=length,则array[i + 1]不存在 73 if (i<length && array[i] < array[i + 1]) 74 i++; 75 if (array[0]>array[i]) break; 76 else 77 { 78 array[k] = array[i]; 79 k = i; 80 } 81 } 82 array[k] = array[0]; 83 } 84 //建立大根堆函数 85 void BuildMaxHeap(int array[], int length) 86 { 87 for (int i = length / 2; i > 0; i--) 88 { 89 AdjustDown(array, i, length); 90 } 91 } 92 //堆排序函数 93 void HeapSort(int array[], int length) 94 { 95 BuildMaxHeap(array, length); 96 for (int i = length; i > 1; i--) 97 { 98 int tmp = array[i]; 99 array[i] = array[1]; 100 array[1] = tmp; 101 AdjustDown(array, 1, i - 1); 102 } 103 }
3.杂论
(1)通常如果我们需要在一大堆元素中取k个最大或最小元素时,都优先采用堆排序。