快速排序的基本思想:
分治法,即,分解,求解,组合 .
分解:
在 无序区R[low..high]中任选一个记录作为基准(通常选第一个记录,并记为keyValue,其下标为keyValuePosition),以此为基准划分成两个较小的 子区间R[low,keyValuePosition- 1]和R[keyValuePosition+
1 , high],并使左边子区间的所有记录均小于等于基准记录,右边子区间的所有记录均大于等于基准记录,基准记录无需参加后续的排序。而划分的关键是要求出 基准记录所在的位置keyValuePosition.
求解:
通过递归调用快速排序对左、右子区间R[low..keyValuePosition-1]和R[keyValuePosition+1..high]快速排序
组合:
当"求解"步骤中的两个递归调用结束时,其左、右两个子区间已有序。对快速排序而言,"组合"步骤无须做什么,可看作是空操作。
具体过程:
设序列为R[low,high],从其中选第一个为基准,设为keyValue,然后设两个指针i和j,分别指向序列R[low,high]的起始和结束位置上:
1),将i逐渐增大,直到找到大于keyValue的关键字为止;
2),将j逐渐减少,直到找到小于等于keyValue的关键字为止;
3),如果i<j,即R[i,j]的元素数大于1,则交换R[i]和R[j];
4),将基准记录keyValue放到合适的位置上,即i和j同时指向的位置(或者同时指向的位置-1),则此位置为新的keyValuePosition。
备注:
快速排序是不稳定排序,即相同的关键字排序后,相对位置是不确定的。
下面是我的C#实现的代码
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace QuickSort 7 { 8 class QuickSort 9 { 10 static void Main(string[] args) 11 { 12 //声明数据进行相应的测试 13 int[] myArray = new int[]{45, 36, 18, 53, 72, 30, 48, 93, 15, 36}; 14 //myArray = new int[] { 3, 4, 5, 1}; 15 //myArray = new int[] { 3, 4, 2, 1}; 16 17 int lowIndex = 0; //数组的起始位置(从0开始) 18 int highIndex = myArray.Length - 1; //数组的终止位置 19 20 //快速排序 21 QuickSortFunction(myArray, lowIndex, highIndex); 22 23 //输出排完之后的数组 24 for (int i = 0; i < myArray.Length; i++) 25 { 26 Console.WriteLine(myArray[i].ToString()); 27 } 28 } 29 30 //快速排序(目标数组,数组的起始位置,数组的终止位置) 31 private static void QuickSortFunction(int[] array, int low, int high) 32 { 33 try 34 { 35 int keyValuePosition; //记录关键值的下标 36 37 //当传递的目标数组含有两个以上的元素时,进行递归调用。(即:当传递的目标数组只含有一个元素时,此趟排序结束) 38 if (low < high) 39 { 40 keyValuePosition = keyValuePositionFunction(array, low, high); //获取关键值的下标(快排的核心) 41 42 QuickSortFunction(array, low, keyValuePosition - 1); //递归调用,快排划分出来的左区间 43 QuickSortFunction(array, keyValuePosition + 1, high); //递归调用,快排划分出来的右区间 44 } 45 } 46 catch (Exception ex) 47 { } 48 } 49 50 //快速排序的核心部分:确定关键值在数组中的位置,以此将数组划分成左右两区间,关键值游离在外。(返回关键值应在数组中的下标) 51 private static int keyValuePositionFunction(int[] array, int low, int high) 52 { 53 int leftIndex = low; //记录目标数组的起始位置(后续动态的左侧下标) 54 int rightIndex = high; //记录目标数组的结束位置(后续动态的右侧下标) 55 56 int keyValue = array[low]; //数组的第一个元素作为关键值 57 int temp; 58 59 //当 (左侧动态下标 == 右侧动态下标) 时跳出循环 60 while (leftIndex < rightIndex) 61 { 62 while (leftIndex < rightIndex && array[leftIndex] <= keyValue) //左侧动态下标逐渐增加,直至找到大于keyValue的下标 63 { 64 leftIndex++; 65 } 66 while (leftIndex < rightIndex && array[rightIndex] > keyValue) //右侧动态下标逐渐减小,直至找到小于或等于keyValue的下标 67 { 68 rightIndex--; 69 } 70 if(leftIndex < rightIndex) //如果leftIndex < rightIndex,则交换左右动态下标所指定的值;当leftIndex==rightIndex时,跳出整个循环 71 { 72 temp = array[leftIndex]; 73 array[leftIndex] = array[rightIndex]; 74 array[rightIndex] = temp; 75 } 76 } 77 78 //当左右两个动态下标相等时(即:左右下标指向同一个位置),此时便可以确定keyValue的准确位置 79 temp = keyValue; 80 if (temp < array[rightIndex]) //当keyValue < 左右下标同时指向的值,将keyValue与rightIndex - 1指向的值交换,并返回rightIndex - 1 81 { 82 array[low] = array[rightIndex - 1]; 83 array[rightIndex - 1] = temp; 84 return rightIndex - 1; 85 } 86 else //当keyValue >= 左右下标同时指向的值,将keyValue与rightIndex指向的值交换,并返回rightIndex 87 { 88 array[low] = array[rightIndex]; 89 array[rightIndex] = temp; 90 return rightIndex; 91 } 92 } 93 } 94 }