标签:des style blog http color io os ar 使用
各种排序算法:冒择路(入)兮(稀)快归堆,桶式排序,基数排序
冒泡排序,选择排序,插入排序,稀尔排序,快速排序,归并排序,堆排序,桶式排序,基数排序
一、冒泡排序(BubbleSort)
1. 基本思想:
两两比较待排序数据元素的大小,发现两个数据元素的次序相反时即进行交换,直到没有反序的数据元素为止。
2. 排序过程:
设想被排序的数组R[1..N]垂直竖立,将每个数据元素看作有重量的气泡,根据轻气泡不能在重气泡之下的原则,从下往上扫描数组R,凡扫描到违反本原则的轻气泡,就使其向上"漂浮",如此反复进行,直至最后任何两个气泡都是轻者在上,重者在下为止。
【示例】:
49 13 13 13 13 13 13 13
38 49 27 27 27 27 27 27
65 38 49 38 38 38 38 38
97 65 38 49 49 49 49 49
76 97 65 49 49 49 49 49
13 76 97 65 65 65 65 65
27 27 76 97 76 76 76 76
49 49 49 76 97 97 97 97
java代码实现:
-
- public class BubbleSort {
-
-
- public void bubble(Integer[] array, int from, int end) {
-
- for (int k = 1; k < end - from + 1; k++) {
-
- for (int i = end - from; i >= k; i--) {
-
- if ((array[i].compareTo(array[i - 1])) < 0) {
-
- swap(array, i, i - 1);
- }
- }
- }
- }
-
-
- public void swap(Integer[] array, int i, int j) {
- if (i != j) {
- Integer tmp = array[i];
- array[i] = array[j];
- array[j] = tmp;
- }
- }
-
-
-
- public static void main(String[] args) {
- Integer[] intgArr = { 7, 2, 4, 3, 12, 1, 9, 6, 8, 5, 11, 10 };
- BubbleSort bubblesort = new BubbleSort();
- bubblesort.bubble(intgArr,0,intgArr.length-1);
- for(Integer intObj:intgArr){
- System.out.print(intObj + " ");
- }
- }
- }
另外一种实现方式:
- public class BubbleSort2{
- public static void main(String[] args){
- int[] a = {3,5,9,4,7,8,6,1,2};
- BubbleSort2 bubble = new BubbleSort2();
- bubble.bubble(a);
- for(int num:a){
- System.out.print(num + " ");
- }
- }
-
- public void bubble(int[] a){
- for(int i=a.length-1;i>0;i--){
- for(int j=0;j<i;j++){
- if(new Integer(a[j]).compareTo(new Integer(a[j+1]))>0){
- swap(a,j,j+1);
- }
- }
- }
- }
-
- public void swap(int[] a,int x,int y){
- int temp;
- temp=a[x];
- a[x]=a[y];
- a[y]=temp;
- }
- }
二、选择排序
1. 基本思想:
每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。
2. 排序过程:
【示例】:
初始关键字 [49 38 65 97 76 13 27 49]
第一趟排序后 13 [38 65 97 76 49 27 49]
第二趟排序后 13 27 [65 97 76 49 38 49]
第三趟排序后 13 27 38 [97 76 49 65 49]
第四趟排序后 13 27 38 49 [49 97 65 76]
第五趟排序后 13 27 38 49 49 [97 97 76]
第六趟排序后 13 27 38 49 49 76 [76 97]
第七趟排序后 13 27 38 49 49 76 76 [ 97]
最后排序结果 13 27 38 49 49 76 76 97
java代码实现:
- public class SelectSort {
-
-
- public void select(Integer[] array) {
- int minIndex;
-
- for (int i=0; i<array.length; i++) {
- minIndex = i;
-
- for (int j=i+1;j<array.length; j++) {
-
- if ((array[j].compareTo(array[minIndex])) < 0) {
- minIndex = j;
- }
- }
-
-
- swap(array, i, minIndex);
- }
- }
-
- public static void swap(Integer[] intgArr,int x,int y){
-
- int temp;
- temp=intgArr[x];
- intgArr[x]=intgArr[y];
- intgArr[y]=temp;
- }
-
-
- public static void main(String[] args) {
- Integer[] intgArr = { 5, 9, 1, 4, 2, 6, 3, 8, 0, 7 };
- SelectSort insertSort = new SelectSort();
- insertSort.select(intgArr);
- for(Integer intObj:intgArr){
- System.out.print(intObj + " ");
- }
-
- }
- }
三、插入排序(Insertion Sort)
1. 基本思想:
每次将一个待排序的数据元素,插入到前面已经排好序的数列中的适当位置,使数列依然有序;直到待排序数据元素全部插入完为止。
2. 排序过程:
【示例】:
[初始关键字] [49] 38 65 97 76 13 27 49
J=2(38) [38 49] 65 97 76 13 27 49
J=3(65) [38 49 65] 97 76 13 27 49
J=4(97) [38 49 65 97] 76 13 27 49
J=5(76) [38 49 65 76 97] 13 27 49
J=6(13) [13 38 49 65 76 97] 27 49
J=7(27) [13 27 38 49 65 76 97] 49
J=8(49) [13 27 38 49 49 65 76 97]
java代码实现:
-
- public class InsertSort {
-
-
- public void insert(Integer[] array, int from, int end) {
-
-
- for (int i=from+1; i<=end; i++) {
-
- for (int j = 0; j < i; j++) {
- Integer insertedElem = array[i];
-
- if ((array[j].compareTo(insertedElem)) > 0) {
-
- move(array, j, i - 1);
-
- array[j] = insertedElem;
- break;
- }
- }
- }
-
-
-
-
- }
-
-
-
- public void move(Integer[] array, int startIndex, int endIndex) {
- for (int i = endIndex; i >= startIndex; i--) {
- array[i+1] = array[i];
- }
- }
-
-
-
- public static void main(String[] args) {
- Integer[] intgArr = { 5, 9, 1, 4, 2, 6, 3, 8, 0, 7 };
- InsertSort insertSort = new InsertSort();
- insertSort.insert(intgArr,0,intgArr.length-1);
- for(Integer intObj:intgArr){
- System.out.print(intObj + " ");
- }
- }
- }
四、稀尔排序
转自:http://blog.csdn.net/morewindows/article/details/6668714
希尔排序的实质就是分组插入排序,该方法又称缩小增量排序,因DL.Shell于1959年提出而得名。
该
方法的基本思想是:先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整
个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。因为直接插入排序在元素基本有序的情况下(接近最好情况),效率是很高的,
因此希尔排序在时间效率上比前两种方法有较大提高。
以n=10的一个数组49, 38, 65, 97, 26, 13, 27, 49, 55, 4为例
第一次 gap = 10 / 2 = 5
49 38 65 97 26 13 27 49 55 4
1A 1B
2A 2B
3A 3B
4A 4B
5A 5B
1A,1B,2A,2B
等为分组标记,数字相同的表示在同一组,大写字母表示是该组的第几个元素, 每次对同一组的数据进行直接插入排序。即分成了五组(49, 13)
(38, 27) (65, 49) (97, 55) (26, 4)这样每组排序后就变成了(13, 49)
(27, 38) (49, 65) (55, 97) (4, 26),下同。
第二次 gap = 5 / 2 = 2
排序后
13 27 49 55 4 49 38 65 97 26
1A 1B 1C 1D 1E
2A 2B 2C 2D 2E
第三次 gap = 2 / 2 = 1
4 26 13 27 38 49 49 55 97 65
1A 1B 1C 1D 1E 1F 1G 1H 1I 1J
第四次 gap = 1 / 2 = 0 排序完成得到数组:
4 13 26 27 38 49 49 55 65 97
下面给出严格按照定义来写的希尔排序
-
voidintint
int
for
-
for
-
for
if
int
int
while
}
很
明显,上面的shellsort1代码虽然对直观的理解希尔排序有帮助,但代码量太大了,不够简洁清晰。因此进行下改进和优化,以第二次排序为例,原来是
每次从1A到1E,从2A到2E,可以改成从1B开始,先和1A比较,然后取2B与2A比较,再取1C与前面自己组内的数据比较…….。这种每次从数组第
gap个元素开始,每个元素与自己组内的数据进行直接插入排序显然也是正确的。
-
voidintint
int
for
for
-
if
-
int
int
while
}
再将直接插入排序部分用 白话经典算法系列之二 直接插入排序的三种实现 中直接插入排序的第三种方法来改写下:
-
voidintint
int
for
for
for
}
这样代码就变得非常简洁了。
附注:上面希尔排序的步长选择都是从n/2开始,每次再减半,直到最后为1。其实也可以有另外的更高效的步长选择,如果读者有兴趣了解,请参阅维基百科上对希尔排序步长的说明:
http://zh.wikipedia.org/wiki/%E5%B8%8C%E5%B0%94%E6%8E%92%E5%BA%8F
java代码实现:
- public class ShellSort {
-
-
- public void sort(Integer[] array, int from, int end) {
-
- int step = initialStep(end - from + 1);
-
-
- for (; step >= 1; step = (step + 1) / 2 - 1) {
-
- for (int groupIndex = 0; groupIndex < step; groupIndex++) {
-
-
- insertSort(array, groupIndex, step, end);
- }
- }
- }
-
-
- public void insertSort(Integer[] array, int groupIndex, int step, int end) {
- int startIndex = groupIndex;
- int endIndex = startIndex;
-
- while ((endIndex + step) <= end) {
- endIndex += step;
- }
-
-
- for (int i = groupIndex + step; i <= end; i += step) {
- for (int j = groupIndex; j < i; j += step) {
- Integer insertedElem = array[i];
-
- if ((array[j].compareTo(insertedElem)) >= 0) {
-
- move(array, j, i - step, step);
- array[j] = insertedElem;
- break;
- }
- }
- }
- }
-
-
- public static int initialStep(int len) {
-
- int step = 1;
-
-
- while ((step + 1) * 2 - 1 < len - 1) {
- step = (step + 1) * 2 - 1;
- }
-
- System.out.println("初始步长 : " + step);
- return step;
- }
-
-
- protected final void move(Integer[] array, int startIndex, int endIndex, int step) {
- for (int i = endIndex; i >= startIndex; i -= step) {
- array[i + step] = array[i];
- }
- }
-
-
-
- public static void main(String[] args) {
- Integer[] intgArr = { 5, 9, 1, 4, 8, 2, 6, 3, 7, 0 };
- ShellSort shellSort = new ShellSort();
- shellSort.sort(intgArr,0,intgArr.length-1);
- for(Integer intObj:intgArr){
- System.out.print(intObj + " ");
- }
- }
- }
五、快速排序(Quick Sort)
1. 基本思想:
在当前无序区R[1..H]中任取一个数据元素作为比较的"基准"(不妨记为X),用此基准将当前无序区划分为左右两个较小的无序区:R[1..I-
1]和R[I+1..H],且左边的无序子区中数据元素均小于等于基准元素,右边的无序子区中数据元素均大于等于基准元素,而基准X则位于最终排序的位置
上,即R[1..I-1]≤X.Key≤R[I+1..H](1≤I≤H),当R[1..I-1]和R[I+1..H]均非空时,分别对它们进行上述的划
分过程,直至所有无序子区中的数据元素均已排序为止。
2. 排序过程:
【示例】:
初始关键字 [49 38 65 97 76 13 27 49]
一趟排序之后 [27 38 13] 49 [76 97 65 49]
二趟排序之后 [13] 27 [38] 49 [49 65]76 [97]
三趟排序之后 13 27 38 49 49 [65]76 97
最后的排序结果 13 27 38 49 49 65 76 97
各趟排序之后的状态
java代码实现:
-
- public class QuickSort {
-
-
-
- public void sort(Integer[] array, int from, int end) {
- quickSort(array, from, end);
- }
-
-
- private void quickSort(Integer[] array, int low, int high) {
-
- if (low < high) {
-
-
-
- int pivot = partition2(array, low, high);
-
-
-
- quickSort(array, low, pivot - 1);
- quickSort(array, pivot + 1, high);
- }
-
- }
-
-
- private int partition1(Integer[] array, int low, int high) {
- Integer pivotElem = array[low];
-
- int border = low;
-
-
- for (int i = low + 1; i <= high; i++) {
-
- if ((array[i].compareTo(pivotElem)) < 0) {
- swap(array, ++border, i);
- }
- }
-
- swap(array, border, low);
- return border;
- }
-
-
- private int partition2(Integer[] array, int low, int high) {
- int pivot = low;
-
- while (true) {
- if (pivot != high) {
-
- if ((array[high].compareTo(array[pivot])) < 0) {
- swap(array, high, pivot);
-
- pivot = high;
- } else {
- high--;
- }
- } else {
-
- if ((array[low].compareTo(array[pivot])) > 0) {
- swap(array, low, pivot);
-
- pivot = low;
- } else {
- low++;
- }
- }
- if (low == high) {
- break;
- }
- }
-
- return pivot;
- }
-
-
- private int partition3(Integer[] array, int low, int high) {
- int pivot = low;
- low++;
-
-
-
- while (true) {
-
- while (low < high) {
-
- if ((array[low].compareTo(array[pivot])) >= 0) {
- break;
- } else {
- low++;
- }
- }
-
- while (high > low) {
-
- if ((array[high].compareTo(array[pivot])) < 0) {
- break;
- } else {
- high--;
- }
- }
-
- if (low == high) {
- break;
- }
-
- swap(array, low, high);
- }
-
-
- if ((array[pivot].compareTo(array[low])) > 0) {
-
- swap(array, low, pivot);
- pivot = low;
- } else if ((array[pivot].compareTo(array[low])) <= 0) {
- swap(array, low - 1, pivot);
- pivot = low - 1;
- }
-
-
- return pivot;
- }
-
-
- public void swap(Integer[] array, int i, int j) {
- if (i != j) {
- Integer tmp = array[i];
- array[i] = array[j];
- array[j] = tmp;
- }
- }
-
-
- public static void main(String[] args) {
- Integer[] intgArr = { 5, 9, 1, 4, 2, 6, 3, 8, 0, 7 };
- QuickSort quicksort = new QuickSort();
- quicksort.sort(intgArr,0,intgArr.length-1);
- for(Integer intObj:intgArr){
- System.out.print(intObj + " ");
- }
- }
- }
六、归并排序
归并排序:归并算法的中心是归并两个已经有序的数组,并且递归调用归并操作。
优点和缺点:比简单排序在速度上快很多;归并排序会占用双倍的存储空间。
效率:归并排序的时间复杂度是
O(N*LogN);简单排序的复杂度是O(N2)。
每一趟归并的时间复杂度为 O(n), 需要O(logn)次归并
如图所示:
[3 1 4 1 5 9 2 7]
/ \
[3 1 4 1] [5 9 2 7]
/ \ / \
[3 1] [4 1] [5 9] [2 7]
/ \ / \ / \ / \
[3] [1] [4] [1] [5] [9] [2] [7]
\ / \ / \ / \ /
[1 3] [1 4] [5 9] [2 7]
\ / \ /
[1 1 3 4] [2 5 7 9]
\ /
[1 1 2 3 4 5 7 9]
java代码实现:
- public class MergeSort{
-
-
- public void partition(Integer[] arr, int from, int end) {
-
- if (from < end) {
-
- int mid = (from + end) / 2;
- partition(arr, from, mid);
- partition(arr, mid + 1, end);
-
- merge(arr, from, end, mid);
- }
- }
-
-
- public void merge(Integer[] arr, int from, int end, int mid) {
- Integer[] tmpArr = new Integer[10];
- int tmpArrIndex = 0;
- int part1ArrIndex = from;
- int part2ArrIndex = mid + 1;
-
-
-
- while ((part1ArrIndex <= mid) && (part2ArrIndex <= end)) {
-
- if (arr[part1ArrIndex] - arr[part2ArrIndex] < 0) {
-
-
-
- tmpArr[tmpArrIndex++] = arr[part1ArrIndex++];
- } else {
-
- tmpArr[tmpArrIndex++] = arr[part2ArrIndex++];
- }
- }
-
-
-
- while (part1ArrIndex <= mid) {
- tmpArr[tmpArrIndex++] = arr[part1ArrIndex++];
- }
- while (part2ArrIndex <= end) {
- tmpArr[tmpArrIndex++] = arr[part2ArrIndex++];
- }
-
-
- System.arraycopy(tmpArr, 0, arr, from, end - from + 1);
- }
-
-
- public static void main(String[] args) {
- Integer[] intgArr = {5,9,1,4,2,6,3,8,0,7};
- MergeSort insertSort = new MergeSort();
- insertSort.partition(intgArr,0,intgArr.length-1);
- for(Integer a:intgArr){
- System.out.print(a + " ");
- }
- }
- }
七、堆排序(Heap Sort)
1. 基本思想:
堆排序是一树形选择排序,在排序过程中,将R[1..N]看成是一颗完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的内在关系来选择最小的元素。
2. 堆的定义: N个元素的序列K1,K2,K3,...,Kn.称为堆,当且仅当该序列满足特性:
Ki≤K2i Ki ≤K2i+1(1≤ I≤ [N/2])
堆实质上是满足如下性质的完全二叉树:树中任一非叶子结点的关键字均大于等于其孩子结点的关键字。例如序列10,15,56,25,30,70就是一
个堆,它对应的完全二叉树如上图所示。这种堆中根结点(称为堆顶)的关键字最小,我们把它称为小根堆。反之,若完全二叉树中任一非叶子结点的关键字均大于
等于其孩子的关键字,则称之为大根堆。
3. 排序过程:
堆排序正是利用小根堆(或大根堆)来选取当前无序区中关键字小(或最大)的记录实现排序的。我们不妨利用大根堆来排序。每一趟排序的基本操作是:将当前无
序区调整为一个大根堆,选取关键字最大的堆顶记录,将它和无序区中的最后一个记录交换。这样,正好和直接选择排序相反,有序区是在原记录区的尾部形成并逐
步向前扩大到整个记录区。
【示例】:对关键字序列42,13,91,23,24,16,05,88建堆
java代码实现:
- public class HeapSort {
-
-
- public void sort(Integer[] array, int from, int end) {
-
- initialHeap(array, from, end);
-
-
- for (int i = end - from + 1; i >= 2; i--) {
-
- swap(array, from, i - 1);
-
- adjustNote(array, 1, i - 1);
- }
-
- }
-
-
- private void initialHeap(Integer[] arr, int from, int end) {
- int lastBranchIndex = (end - from + 1) / 2;
-
- for (int i = lastBranchIndex; i >= 1; i--) {
- adjustNote(arr, i, end - from + 1);
- }
- }
-
-
- private void adjustNote(Integer[] arr, int parentNodeIndex, int len) {
- int minNodeIndex = parentNodeIndex;
-
- if (parentNodeIndex * 2 <= len) {
-
- if ((arr[parentNodeIndex - 1].compareTo(arr[parentNodeIndex * 2 - 1])) < 0) {
- minNodeIndex = parentNodeIndex * 2;
- }
-
-
- if (parentNodeIndex * 2 + 1 <= len) {
-
- if ((arr[minNodeIndex - 1].compareTo(arr[(parentNodeIndex * 2 + 1) - 1])) < 0) {
- minNodeIndex = parentNodeIndex * 2 + 1;
- }
- }
- }
-
-
- if (minNodeIndex != parentNodeIndex) {
- swap(arr, parentNodeIndex - 1, minNodeIndex - 1);
-
- if (minNodeIndex * 2 <= len) {
- adjustNote(arr, minNodeIndex, len);
- }
- }
- }
-
-
- public void swap(Integer[] array, int i, int j) {
- if (i != j) {
- Integer tmp = array[i];
- array[i] = array[j];
- array[j] = tmp;
- }
- }
-
-
- public static void main(String[] args) {
- Integer[] intgArr = { 5, 9, 1, 4, 2, 6, 3, 8, 0, 7 };
- HeapSort heapsort = new HeapSort();
- heapsort.sort(intgArr,0,intgArr.length-1);
- for(Integer intObj:intgArr){
- System.out.print(intObj + " ");
- }
- }
-
- }
-
// 新加入i结点 其父结点为(i - 1) / 2
-
void MinHeapFixup(int a[], int i)
-
int j, temp;
-
//父结点
-
while (j >= 0 && i != 0)
-
if (a[j] <= temp)
-
break;
-
//把较大的子结点往下移动,替换它的子结点
-
}
-
void MinHeapFixup(int a[], int i)
-
for (int j = (i - 1) / 2; (j >= 0 && i != 0)&& a[i] > a[j]; i = j, j = (i - 1) / 2)
-
}
-
//在最小堆中加入新的数据nNum
-
void MinHeapAddNumber(int a[], int n, int nNum)
-
}
-
// 从i节点开始调整,n为节点总数 从0开始计算 i节点的子节点为 2*i+1, 2*i+2
-
void MinHeapFixdown(int a[], int i, int n)
-
int j, temp;
-
while (j < n)
-
if (j + 1 < n && a[j + 1] < a[j])
-
if (a[j] >= temp)
-
break;
-
//把较小的子结点往上移动,替换它的父结点
-
//在最小堆中删除数
-
void MinHeapDeleteNumber(int a[], int n)
-
}
-
//建立最小堆
-
void MakeMinHeap(int a[], int n)
-
for (int i = n / 2 - 1; i >= 0; i--)
-
}
-
void MinheapsortTodescendarray(int a[], int n)
-
for (int i = n - 1; i >= 1; i--)
-
}
- public class BucketSort {
- public void sort(int[] keys,int from,int len,int max)
- {
- int[] temp=new int[len];
- int[] count=new int[max];
-
-
- for(int i=0;i<len;i++)
- {
- count[keys[from+i]]++;
- }
-
- for(int i=1;i<max;i++)
- {
- count[i]=count[i]+count[i-1];
- }
-
- System.arraycopy(keys, from, temp, 0, len);
- for(int k=len-1;k>=0;k--)
- {
- keys[--count[temp[k]]]=temp[k];
- }
- }
-
- public static void main(String[] args) {
-
- int[] a={1,4,8,3,2,9,5,0,7,6,9,10,9,13,14,15,11,12,17,16};
- BucketSort bucketSort=new BucketSort();
- bucketSort.sort(a,0,a.length,20);
-
-
- for(int i=0;i<a.length;i++)
- {
- System.out.print(a[i]+",");
- }
-
- }
-
-
- }
九、基数排序
java代码实现:
- import java.util.Arrays;
- public class RadixSort {
-
-
- public int digit(long x, long d) {
-
- long pow = 1;
- while (--d > 0) {
- pow *= 10;
- }
- return (int) (x / pow % 10);
- }
-
-
- public long[] radixSortAsc(long[] arr) {
-
- for (int d = 1; d <= getMax(arr); d++) {
-
- long[] tmpArray = new long[arr.length];
-
- int[] count = new int[10];
-
- for (int i = 0; i < arr.length; i++) {
- count[digit(arr[i], d)] += 1;
- }
-
- for (int i = 1; i < 10; i++) {
- count[i] += count[i - 1];
- }
-
-
- for (int i = arr.length - 1; i >= 0; i--) {
-
- tmpArray[count[digit(arr[i], d)] - 1] = arr[i];
- count[digit(arr[i], d)]--;
- }
-
- System.arraycopy(tmpArray, 0, arr, 0, tmpArray.length);
- }
- return arr;
- }
-
-
- public long[] radixSortDesc(long[] arr) {
- for (int d = 1; d <= getMax(arr); d++) {
- long[] tmpArray = new long[arr.length];
-
- int[] count = new int[10];
-
-
- for (int i = 0; i < arr.length; i++) {
- count[9 - digit(arr[i], d)] += 1;
- }
-
- for (int i = 1; i < 10; i++) {
- count[i] += count[i - 1];
- }
-
- for (int i = arr.length - 1; i >= 0; i--) {
- tmpArray[count[9 - digit(arr[i], d)] - 1] = arr[i];
- count[9 - digit(arr[i], d)]--;
- }
-
- System.arraycopy(tmpArray, 0, arr, 0, tmpArray.length);
- }
- return arr;
- }
-
- private int getMax(long[] array) {
- int maxlIndex = 0;
- for (int j = 1; j < array.length; j++) {
- if (array[j] > array[maxlIndex]) {
- maxlIndex = j;
- }
- }
- return String.valueOf(array[maxlIndex]).length();
- }
-
- public static void main(String[] args) {
- long[] ary = new long[] { 123, 321, 132, 212, 213, 312, 21, 223 };
- RadixSort rs = new RadixSort();
- System.out.println("升 - " + Arrays.toString(rs.radixSortAsc(ary)));
-
- ary = new long[] { 123, 321, 132, 212, 213, 312, 21, 223 };
- System.out.println("降 - " + Arrays.toString(rs.radixSortDesc(ary)));
- }
- }
十、几种排序算法的比较和选择
1. 选取排序方法需要考虑的因素:
(1) 待排序的元素数目n;
(2) 元素本身信息量的大小;
(3) 关键字的结构及其分布情况;
(4) 语言工具的条件,辅助空间的大小等。
2. 小结:
(1) 若n较小(n <= 50),则可以采用直接插入排序或直接选择排序。由于直接插入排序所需的记录移动操作较直接选择排序多,因而当记录本身信息量较大时,用直接选择排序较好。
(2) 若文件的初始状态已按关键字基本有序,则选用直接插入或冒泡排序为宜。
(3) 若n较大,则应采用时间复杂度为O(nlog2n)的排序方法:快速排序、堆排序或归并排序。 快速排序是目前基于比较的内部排序法中被认为是最好的方法。
(4) 在基于比较排序方法中,每次比较两个关键字的大小之后,仅仅出现两种可能的转移,因此可以用一棵二叉树来描述比较判定过程,由此可以证明:当文件的n个关键字随机分布时,任何借助于"比较"的排序算法,至少需要O(nlog2n)的时间。
(5) 当记录本身信息量较大时,为避免耗费大量时间移动记录,可以用链表作为存储结构。
排序简介
排序是数据处理中经常使用的一种重要运算,在计算机及其应用系统中,花费在排序上的时间在系统运行时间中占有很大比重;
并且排序本身对推动算法分析的发展也起很大作用。目前已有上百种排序方法,但尚未有一个最理想的尽如人意的方法,本章介绍常用的如下排序方法,并对它们进
行分析和比较。
1、插入排序(直接插入排序、折半插入排序、希尔排序);
2、交换排序(起泡排序、快速排序);
3、选择排序(直接选择排序、堆排序);
4、归并排序;
5、基数排序;
学习重点
1、掌握排序的基本概念和各种排序方法的特点,并能加以灵活应用;
2、掌握插入排序(直接插入排序、折半插入排序、希尔排序)、交换排序(起泡排序、快速排序)、选择排序(直接选择排序、堆排序)、二路归并排序的方法及其性能分析方法;
3、了解基数排序方法及其性能分析方法。
排序(sort)或分类
所谓排序,就是要整理文件中的记录,使之按关键字递增(或递减)次序排列起来。其确切定义如下:
输入:n个记录R1,R2,…,Rn,其相应的关键字分别为K1,K2,…,Kn。
输出:Ril,Ri2,…,Rin,使得Ki1≤Ki2≤…≤Kin。(或Ki1≥Ki2≥…≥Kin)。
1.被排序对象--文件
被排序的对象--文件由一组记录组成。
记录则由若干个数据项(或域)组成。其中有一项可用来标识一个记录,称为关键字项。该数据项的值称为关键字(Key)。
注意:
在不易产生混淆时,将关键字项简称为关键字。
2.排序运算的依据--关键字
用来作排序运算依据的关键字,可以是数字类型,也可以是字符类型。
关键字的选取应根据问题的要求而定。
【例】在高考成绩统计中将每个考生作为一个记录。每条记录包含准考证号、姓名、各科的分数和总分数等项内容。若要惟一地标识一个考生的记录,则必须用"准考证号"作为关键字。若要按照考生的总分数排名次,则需用"总分数"作为关键字。
排序的稳定性
当待排序记录的关键字均不相同时,排序结果是惟一的,否则排序结果不唯一。
在待排序的文件中,若存在多个关键字相同的记录,经过排序后这些具有相同关键字的记录之间的相对次序保持不变,该排序方法是稳定的;若具有相同关键字的记录之间的相对次序发生变化,则称这种排序方法是不稳定的。
注意:
排序算法的稳定性是针对所有输入实例而言的。即在所有可能的输入实例中,只要有一个实例使得算法不满足稳定性要求,则该排序算法就是不稳定的。
排序方法的分类
1.按是否涉及数据的内、外存交换分
在排序过程中,若整个文件都是放在内存中处理,排序时不涉及数据的内、外存交换,则称之为内部排序(简称内排序);反之,若排序过程中要进行数据的内、外存交换,则称之为外部排序。
注意:
① 内排序适用于记录个数不很多的小文件
② 外排序则适用于记录个数太多,不能一次将其全部记录放人内存的大文件。
2.按策略划分内部排序方法
可以分为五类:插入排序、选择排序、交换排序、归并排序和分配排序。
排序算法分析
1.排序算法的基本操作
大多数排序算法都有两个基本的操作:
(1) 比较两个关键字的大小;
(2) 改变指向记录的指针或移动记录本身。
注意:
第(2)种基本操作的实现依赖于待排序记录的存储方式。
2.待排文件的常用存储方式
(1) 以顺序表(或直接用向量)作为存储结构
排序过程:对记录本身进行物理重排(即通过关键字之间的比较判定,将记录移到合适的位置)
(2) 以链表作为存储结构
排序过程:无须移动记录,仅需修改指针。通常将这类排序称为链表(或链式)排序;
(3) 用顺序的方式存储待排序的记录,但同时建立一个辅助表(如包括关键字和指向记录位置的指针组成的索引表)
排序过程:只需对辅助表的表目进行物理重排(即只移动辅助表的表目,而不移动记录本身)。适用于难于在链表上实现,仍需避免排序过程中移动记录的排序方法。
3.排序算法性能评价
(1) 评价排序算法好坏的标准
评价排序算法好坏的标准主要有两条:
① 执行时间和所需的辅助空间
② 算法本身的复杂程度
(2) 排序算法的空间复杂度
若排序算法所需的辅助空间并不依赖于问题的规模n,即辅助空间是O(1),则称之为就地排序(In-PlaceSou)。
非就地排序一般要求的辅助空间为O(n)。
(3) 排序算法的时间开销
大多数排序算法的时间开销主要是关键字之间的比较和记录的移动。有的排序算法其执行时间不仅依赖于问题的规模,还取决于输入实例中数据的状态。
文件的顺序存储结构表示
#define n l00 //假设的文件长度,即待排序的记录数目
typedef int KeyType; //假设的关键字类型
typedef struct{ //记录类型
KeyType key; //关键字项
InfoType otherinfo;//其它数据项,类型InfoType依赖于具体应用而定义
}RecType;
typedef RecType SeqList[n+1];//SeqList为顺序表类型,表中第0个单元一般用作哨兵
注意:
若关键字类型没有比较算符,则可事先定义宏或函数来表示比较运算。
【例】关键字为字符串时,可定义宏"#define LT(a,b)(Stromp((a),(b))<0)"。那么算法中"a<b"可用"LT(a,b)"取代。若使用C++,则定义重载的算符"<"更为方便。
按平均时间将排序分为四类:
(1)平方阶(O(n2))排序
一般称为简单排序,例如直接插入、直接选择和冒泡排序;
(2)线性对数阶(O(nlgn))排序
如快速、堆和归并排序;
(3)O(n1+£)阶排序
£是介于0和1之间的常数,即0<£<1,如希尔排序;
(4)线性阶(O(n))排序
如桶、箱和基数排序。
各种排序方法比较
简单排序中直接插入最好,快速排序最快,当文件为正序时,直接插入和冒泡均最佳。
影响排序效果的因素
因为不同的排序方法适应不同的应用环境和要求,所以选择合适的排序方法应综合考虑下列因素:
①待排序的记录数目n;
②记录的大小(规模);
③关键字的结构及其初始状态;
④对稳定性的要求;
⑤语言工具的条件;
⑥存储结构;
⑦时间和辅助空间复杂度等。
不同条件下,排序方法的选择
(1)若n较小(如n≤50),可采用直接插入或直接选择排序。
当记录规模较小时,直接插入排序较好;否则因为直接选择移动的记录数少于直接插人,应选直接选择排序为宜。
(2)若文件初始状态基本有序(指正序),则应选用直接插人、冒泡或随机的快速排序为宜;
(3)若n较大,则应采用时间复杂度为O(nlgn)的排序方法:快速排序、堆排序或归并排序。
快速排序是目前基于比较的内部排序中被认为是最好的方法,当待排序的关键字是随机分布时,快速排序的平均时间最短;
堆排序所需的辅助空间少于快速排序,并且不会出现快速排序可能出现的最坏情况。这两种排序都是不稳定的。
若要求排序稳定,则可选用归并排序。但本章介绍的从单个记录起进行两两归并的
排序算法并不值得提倡,通常可以将它和直接插入排序结合在一起使用。先利用直接插入排序求得较长的有序子文件,然后再两两归并之。因为直接插入排序是稳定
的,所以改进后的归并排序仍是稳定的。
4)在基于比较的排序方法中,每次比较两个关键字的大小之后,仅仅出现两种可能的转移,因此可以用一棵二叉树来描述比较判定过程。
当文件的n个关键字随机分布时,任何借助于"比较"的排序算法,至少需要O(nlgn)的时间。
箱排序和基数排序只需一步就会引起m种可能的转移,即把一个记录装入m个箱子之一,因此在一般情况下,箱排序和基数排序可能在O(n)时间内完成对n个
记录的排序。但是,箱排序和基数排序只适用于像字符串和整数这类有明显结构特征的关键字,而当关键字的取值范围属于某个无穷集合(例如实数型关键字)时,
无法使用箱排序和基数排序,这时只有借助于"比较"的方法来排序。
若n很大,记录的关键字位数较少且可以分解时,采用基数排序较好。虽然桶排序对关键字的结构无要求,但它也只有在关键字是随机分布时才能使平均时间达到
线性阶,否则为平方阶。同时要注意,箱、桶、基数这三种分配排序均假定了关键字若为数字时,则其值均是非负的,否则将其映射到箱(桶)号时,又要增加相应
的时间。
(5)有的语言(如Fortran,Cobol或Basic等)没有提供指针及递归,导致实现归并、快速(它们用递归实现较简单)和基数(使用了指针)等排序算法变得复杂。此时可考虑用其它排序。
(6)本章给出的排序算法,输人数据均是存储在一个向量中。当记录的规模较大时,为避免耗费大量的时间去移动记录,可以用链表作为存储结构。譬如插入排
序、归并排序、基数排序都易于在链表上实现,使之减少记录的移动次数。但有的排序方法,如快速排序和堆排序,在链表上却难于实现,在这种情况下,可以提取
关键字建立索引表,然后对索引表进行排序。然而更为简单的方法是:引人一个整型向量t作为辅助表,排序前令t[i]=i(0≤i<n),若排序算法
中要求交换R[i]和R[j],则只需交换t[i]和t[j]即可;排序结束后,向量t就指示了记录之间的顺序关系:
R[t[0]].key≤R[t[1]].key≤…≤R[t[n-1]].key
若要求最终结果是:
R[0].key≤R[1].key≤…≤R[n-1].key
则可以在排序结束后,再按辅助表所规定的次序重排各记录,完成这种重排的时间是O(n)。
Java 排序算法
标签:des style blog http color io os ar 使用
原文地址:http://www.cnblogs.com/maple42/p/4045530.html