摘要: 排序算法最能体现算法的多样性。
1. 代码先上代码, 再说废话.
#include2. 运行结果#include #define TABLE_SIZE 19 typedef struct Node{ int key; char value; }Node, *NodePtr; typedef struct SequentialList{ int length; NodePtr elements; }SequentialList, *ListPtr; ListPtr initList(int* paraKeys, char* paraValues, int paraLength){ int i; ListPtr resultPtr = (ListPtr)malloc(sizeof(struct SequentialList)); resultPtr->length = paraLength; resultPtr->elements = (NodePtr)malloc(paraLength * sizeof(struct Node)); for (i = 0; i < paraLength; i ++){ //printf("setting key for index %d: %d and value: %crn", i, paraKeys[i], paraValues[i]); resultPtr->elements[i].key = paraKeys[i]; resultPtr->elements[i].value = paraValues[i]; }//Of for i return resultPtr; }//Of initList void printList(ListPtr paraPtr) { int i; printf("(Keys, values)rn"); for (i = 0; i < paraPtr->length; i ++) { printf("%dt", paraPtr->elements[i].key); }//Of for i printf("rn"); for (i = 0; i < paraPtr->length; i ++) { printf("%ct", paraPtr->elements[i].value); }//Of for i }//Of printList void insertionSort(ListPtr paraPtr) { Node tempNode; int j; for (int i = 2; i < paraPtr->length; i++) { tempNode = paraPtr->elements[i]; //Find the position to insert. //At the same time, move other nodes. for (j = i - 1; paraPtr->elements[j].key > tempNode.key; j--) { paraPtr->elements[j + 1] = paraPtr->elements[j]; } // Of for j //Insert. paraPtr->elements[j + 1] = tempNode; } // Of for i }// Of insertionSort void insertionSortTest() { int tempUnsortedKeys[] = { -100, 5, 3, 6, 10, 7, 1, 9 }; char tempContents[] = { 'n', 'i', 't', 'e', 's', 'c', 'f', 'w' }; ListPtr tempList = initList(tempUnsortedKeys, tempContents, 8); printf("rnBefore insertion sort:rn"); printList(tempList); insertionSort(tempList); printf("rnAfter insertion sort:rn"); printList(tempList); }// Of insertionSortTest void shellSort(ListPtr paraPtr) { Node tempNode; int tempJumpArray[] = { 5, 3, 1 }; int tempJump; int p, i, j, k; for (i = 0; i < 3; i++) { tempJump = tempJumpArray[i]; for (j = 0; j < tempJump; j++) { for (k = j + tempJump; k < paraPtr->length; k += tempJump) { tempNode = paraPtr->elements[k]; // Find the position to insert. // At the same time, move other nodes. for (p = k - tempJump; p >= 0; p -= tempJump) { if (paraPtr->elements[p].key > tempNode.key) { paraPtr->elements[p + tempJump] = paraPtr->elements[p]; } else { break; } // Of if } // Of for p // Insert. paraPtr->elements[p + tempJump] = tempNode; } // Of for k } // Of for j } // Of for i }// Of shellSort void shellSortTest() { int tempUnsortedKeys[] = {5, 3, 6, 10, 7, 1, 9 }; char tempContents[] = {'i', 't', 'e', 's', 'c', 'f', 'w' }; ListPtr tempList = initList(tempUnsortedKeys, tempContents, 7); printf("rnBefore shell sort:rn"); printList(tempList); shellSort(tempList); printf("rnAfter shell sort:rn"); printList(tempList); }// Of shellSortTest void bubbleSort(ListPtr paraPtr) { bool tempSwapped; Node tempNode; int i, j; for (i = paraPtr->length - 1; i > 0; i--) { tempSwapped = false; for (j = 0; j < i; j++) { if (paraPtr->elements[j].key > paraPtr->elements[j + 1].key) { // Swap. tempNode = paraPtr->elements[j + 1]; paraPtr->elements[j + 1] = paraPtr->elements[j]; paraPtr->elements[j] = tempNode; tempSwapped = true; } // Of if } // Of for j // No swap in this round. The data are already sorted. if (!tempSwapped) { printf("Premature.rn"); break; } // Of if } // Of for i }// Of bubbleSort void bubbleSortTest() { int tempUnsortedKeys[] = {5, 3, 6, 10, 7, 1, 9 }; char tempContents[] = {'i', 't', 'e', 's', 'c', 'f', 'w' }; ListPtr tempList = initList(tempUnsortedKeys, tempContents, 7); printf("rnBefore bubble sort:rn"); printList(tempList); shellSort(tempList); printf("rnAfter bubble sort:rn"); printList(tempList); }// Of bubbleSortTest void quickSortRecursive(ListPtr paraPtr, int paraStart, int paraEnd) { int tempPivot, tempLeft, tempRight; Node tempNodeForSwap; // Nothing to sort. if (paraStart >= paraEnd) { return; } // Of if tempPivot = paraPtr->elements[paraEnd].key; tempLeft = paraStart; tempRight = paraEnd - 1; // Find the position for the pivot. // At the same time move smaller elements to the left and bigger one to the // right. while (true) { while ((paraPtr->elements[tempLeft].key < tempPivot) && (tempLeft < tempRight)) { tempLeft++; } // Of while while ((paraPtr->elements[tempRight].key >= tempPivot) && (tempLeft < tempRight)) { tempRight--; } // Of while if (tempLeft < tempRight) { // Swap. //System.out.println("Swapping " + tempLeft + " and " + tempRight); tempNodeForSwap = paraPtr->elements[tempLeft]; paraPtr->elements[tempLeft] = paraPtr->elements[tempRight]; paraPtr->elements[tempRight] = tempNodeForSwap; } else { break; } // Of if } // Of while // Swap if (paraPtr->elements[tempLeft].key > tempPivot) { tempNodeForSwap = paraPtr->elements[paraEnd]; paraPtr->elements[paraEnd] = paraPtr->elements[tempLeft]; paraPtr->elements[tempLeft] = tempNodeForSwap; } else { tempLeft++; } // Of if //System.out.print("From " + paraStart + " to " + paraEnd + ": "); //System.out.println(this); quickSortRecursive(paraPtr, paraStart, tempLeft - 1); quickSortRecursive(paraPtr, tempLeft + 1, paraEnd); }// Of quickSortRecursive void quickSort(ListPtr paraPtr) { quickSortRecursive(paraPtr, 0, paraPtr->length - 1); }// Of quickSort void quickSortTest() { int tempUnsortedKeys[] = {5, 3, 6, 10, 7, 1, 9 }; char tempContents[] = {'i', 't', 'e', 's', 'c', 'f', 'w' }; ListPtr tempList = initList(tempUnsortedKeys, tempContents, 7); printf("rnBefore quick sort:rn"); printList(tempList); quickSort(tempList); printf("rnAfter quick sort:rn"); printList(tempList); }// Of quickSortTest void selectionSort(ListPtr paraPtr) { Node tempNode; int tempIndexForSmallest, i, j; for (i = 0; i < paraPtr->length - 1; i++) { // Initialize. tempNode = paraPtr->elements[i]; tempIndexForSmallest = i; for (j = i + 1; j < paraPtr->length; j++) { if (paraPtr->elements[j].key < tempNode.key) { tempNode = paraPtr->elements[j]; tempIndexForSmallest = j; } // Of if } // Of for j // Change the selected one with the current one. paraPtr->elements[tempIndexForSmallest] = paraPtr->elements[i]; paraPtr->elements[i] = tempNode; } // Of for i }// Of selectionSort void selectionSortTest() { int tempUnsortedKeys[] = {5, 3, 6, 10, 7, 1, 9 }; char tempContents[] = {'i', 't', 'e', 's', 'c', 'f', 'w' }; ListPtr tempList = initList(tempUnsortedKeys, tempContents, 7); printf("rnBefore selection sort:rn"); printList(tempList); selectionSort(tempList); printf("rnAfter selection sort:rn"); printList(tempList); }// Of selectionSortTest void adjustHeap(ListPtr paraPtr, int paraStart, int paraLength) { Node tempNode = paraPtr->elements[paraStart]; int tempParent = paraStart; int tempKey = paraPtr->elements[paraStart].key; for (int tempChild = paraStart * 2 + 1; tempChild < paraLength; tempChild = tempChild * 2 + 1) { // The right child is bigger. if (tempChild + 1 < paraLength) { if (paraPtr->elements[tempChild].key < paraPtr->elements[tempChild + 1].key) { tempChild++; } // Of if } // Of if //System.out.println("The parent position is " + tempParent + " and the child is " + tempChild); if (tempKey < paraPtr->elements[tempChild].key) { // The child is bigger. paraPtr->elements[tempParent] = paraPtr->elements[tempChild]; //System.out.println("Move " + paraPtr->elements[tempChild].key + " to position " + tempParent); tempParent = tempChild; } else { break; } // Of if } // Of for tempChild paraPtr->elements[tempParent] = tempNode; }// Of adjustHeap void heapSort(ListPtr paraPtr) { Node tempNode; int i; // Step 1. Construct the initial heap. for (i = paraPtr->length / 2 - 1; i >= 0; i--) { adjustHeap(paraPtr, i, paraPtr->length); } // Of for i // Step 2. Swap and reconstruct. for (i = paraPtr->length - 1; i > 0; i--) { tempNode = paraPtr->elements[0]; paraPtr->elements[0] = paraPtr->elements[i]; paraPtr->elements[i] = tempNode; adjustHeap(paraPtr, 0, i); //System.out.println("Round " + (length - i) + ": " + this); } // Of for i }// Of heapSort void heapSortTest() { int tempUnsortedKeys[] = {5, 3, 6, 10, 7, 1, 9 }; char tempContents[] = {'i', 't', 'e', 's', 'c', 'f', 'w' }; ListPtr tempList = initList(tempUnsortedKeys, tempContents, 7); printf("rnBefore heap sort:rn"); printList(tempList); heapSort(tempList); printf("rnAfter heap sort:rn"); printList(tempList); }// Of heapSortTest void mergeSort(ListPtr paraPtr) { // Step 1. Allocate space. int tempRow; // The current row int tempGroups; // Number of groups int tempActualRow; // Only 0 or 1 int tempNextRow = 0; int tempGroupNumber; int tempFirstStart, tempSecondStart, tempSecondEnd; int tempFirstIndex, tempSecondIndex; int tempNumCopied; int i; int tempSize; Node** tempMatrix = (Node**)malloc(2 * sizeof(Node*)); tempMatrix[0] = (Node*)malloc(paraPtr->length * sizeof(Node)); tempMatrix[1] = (Node*)malloc(paraPtr->length * sizeof(Node)); for (i = 0; i < paraPtr->length; i ++) { tempMatrix[0][i] = paraPtr->elements[i]; }//Of for i // Step 3. Merge. log n rounds tempRow = -1; for (tempSize = 1; tempSize <= paraPtr->length; tempSize *= 2) { // Reuse the space of the two rows. tempRow++; //System.out.println("Current row = " + tempRow); tempActualRow = tempRow % 2; tempNextRow = (tempRow + 1) % 2; tempGroups = paraPtr->length / (tempSize * 2); if (paraPtr->length % (tempSize * 2) != 0) { tempGroups++; } // Of if //System.out.println("tempSize = " + tempSize + ", numGroups = " + tempGroups); for (tempGroupNumber = 0; tempGroupNumber < tempGroups; tempGroupNumber++) { tempFirstStart = tempGroupNumber * tempSize * 2; tempSecondStart = tempGroupNumber * tempSize * 2 + tempSize; if (tempSecondStart > paraPtr->length - 1) { // Copy the first part. for (i = tempFirstStart; i < paraPtr->length; i++) { tempMatrix[tempNextRow][i] = tempMatrix[tempActualRow][i]; } // Of for i continue; } // Of if tempSecondEnd = tempGroupNumber * tempSize * 2 + tempSize * 2 - 1; if (tempSecondEnd > paraPtr->length - 1) { tempSecondEnd = paraPtr->length - 1; } // Of if tempFirstIndex = tempFirstStart; tempSecondIndex = tempSecondStart; tempNumCopied = 0; while ((tempFirstIndex <= tempSecondStart - 1) && (tempSecondIndex <= tempSecondEnd)) { if (tempMatrix[tempActualRow][tempFirstIndex].key <= tempMatrix[tempActualRow][tempSecondIndex].key) { tempMatrix[tempNextRow][tempFirstStart + tempNumCopied] = tempMatrix[tempActualRow][tempFirstIndex]; tempFirstIndex++; //System.out.println("copying " + tempMatrix[tempActualRow][tempFirstIndex]); } else { tempMatrix[tempNextRow][tempFirstStart + tempNumCopied] = tempMatrix[tempActualRow][tempSecondIndex]; //System.out.println("copying " + tempMatrix[tempActualRow][tempSecondIndex]); tempSecondIndex++; } // Of if tempNumCopied++; } // Of while while (tempFirstIndex <= tempSecondStart - 1) { tempMatrix[tempNextRow][tempFirstStart + tempNumCopied] = tempMatrix[tempActualRow][tempFirstIndex]; tempFirstIndex++; tempNumCopied++; } // Of while while (tempSecondIndex <= tempSecondEnd) { tempMatrix[tempNextRow][tempFirstStart + tempNumCopied] = tempMatrix[tempActualRow][tempSecondIndex]; tempSecondIndex++; tempNumCopied++; } // Of while } // Of for groupNumber } // Of for tempStepSize for (i = 0; i < paraPtr->length; i ++) { paraPtr->elements[i] = tempMatrix[tempNextRow][i]; }//Of for i }// Of mergeSort void mergeSortTest() { int tempUnsortedKeys[] = {5, 3, 6, 10, 7, 1, 9 }; char tempContents[] = {'i', 't', 'e', 's', 'c', 'f', 'w' }; ListPtr tempList = initList(tempUnsortedKeys, tempContents, 7); printf("rnBefore merge sort:rn"); printList(tempList); mergeSort(tempList); printf("rnAfter merge sort:rn"); printList(tempList); }// Of mergeSortTest int main() { insertionSortTest(); //shellSortTest(); //bubbleSortTest(); //quickSortTest(); //selectionSortTest(); //heapSortTest(); //mergeSortTest(); return 1; }// Of main
Before insertion sort: (Keys, values) -100 5 3 6 10 7 1 9 n i t e s c f w After insertion sort: (Keys, values) -100 1 3 5 6 7 9 10 n f t i e c w s Press any key to continue3. 代码说明
好几个算法.
3.1 插入排序- 插入排序是简单直接的排序方式之一. 代码非常短.
- 每次保证前 i 个数据是有序的.
- 先做简单的事情 (第 1 轮最多有 1 次移动), 再做麻烦的事情 (最后一轮最多有 n − 1 n - 1n−1 次移动).
- 下标 0 的数据为岗哨. 比其它排序方式多用一个空间.
- 多达 4 重循环, 但时间复杂度只有 O ( n 2 ) O(n^2 ) O(n2).
- 多次排序反正减少了平均排序时间. 神奇的脑回路.
- 有了昨天的程序铺垫, 本程序写起来也不难.
- 岗哨的个数与最初的步长相关, 我们的程序中为 5. 简便起见我就没用了.
- 可以改变 tempJumpArray.
- 每次确定当前最大值, 也就是确定一个位置的数据.
- 仅交换相邻数据.
- 如果某一趟没有交换, 就表示数据已经有序 (早熟, premature), 可以提前结束了.
- 平均时间复杂度为 O ( n log n ) O(n log n ) O(nlogn), 但最坏情况还是 O ( n 2 ) O(n^2) O(n2).
- Pivot 应该选 (该子序列的) 最后一个元素.
- 递归算法, 每次只能确定 pivot 的位置.
- 判断条件 && (tempLeft < tempRight) 不能少.
- (paraPtr->elements[tempRight].key >= tempPivot) 不能写成 >, 否则出现两个相同 key 时可能出错.
- 又是一个基础 (简单) 算法.
- 与插入排序不同, 先做最麻烦的, 要进行 n − 1 n − 1 n−1 次比较才能获得最小的数据.
- 数据一旦被选择并确定位置, 就不再改变.
- 作为一种简单算法, 其时间复杂度为 O ( n 2 ) O(n^2) O(n2).
- 只需要两个额外的空间来存放最小数据的引用与下标, 因此空间复杂度为 O ( 1 ) O(1) O(1).
- 堆排序可能是排序算法中最难的. 用到了二叉树.
- 建初始堆比较费劲.
- 调整堆的时间复杂度为 O ( log n ) O(log n) O(logn), 所以总体时间复杂度只有 O ( n log n ) O(n log n) O(nlogn).
- 空间复杂度只有 O ( 1 ) O(1) O(1).
- log n log n logn 轮, 每轮 O ( n ) O(n) O(n) 次拷贝. 因此时间复杂度为 O ( n log n ) O(n log n) O(nlogn).
- 空间复杂度为 O ( n ) O(n) O(n). 只需要一行辅助空间.
- 全都是在拷贝引用, 而不是数据本身. 这是 Java 的特性.
- 里面的两重循环总共只有 O ( n ) O(n) O(n). 这里是分成了若干个小组.
- 归并两个有序小组的时候, 用了三个并列的循环.
- 涉及分组后尾巴的各种情况, 所以需要相应的 if 语句.



