排序总结
Posted edviv
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了排序总结相关的知识,希望对你有一定的参考价值。
一.冒泡排序(Bubble Sort):
1.基本思想:
从无序序列头部开始,进行两两比较,根据大小交换位置,知道最后将大(小)的数据元素交换到无需队列的队尾,从而成为有序列表的一部分;下一次继续这个过程,直到所有数据元素都排好序
2.运行过程:
冒泡排序算法的运作如下:
(1)比较相邻的元素。比如第一个比第二个大(小),就交换它们两个。
(2)对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大(小)的数。
(3)针对所有的元素重复以上的步骤,除了最后已选出的元素(有序)。
(4)持续每次对越来越少的元素(无序元素)重复上面的步骤,直到没有任何一对数字需要比较,则序列最终有序。
3.算法实现(核心代码):
1 public int[] bubbleSort(int[] A, int n) 2 for (int i = 0; i < n - 1; i++) 3 for (int j = 0; j < n - i - 1; j++) 4 if (A[j] > A[j + 1]) 5 int temp = A[j]; 6 A[j] = A[j + 1]; 7 A[j + 1] = temp; 8 9 10 11 return A; 12
二.选择排序(Selection Sort):
1.基本思想:
对比数组中前一个元素跟后一个元素的大小,如果后面的元素比前面的元素小(大)则用一个变量k来记住他的位置,接着第二次比较,前面“后一个元素”现变成了“前一个元素”,继续跟他的“后一个元素”进行比较,如果后面的元素比他要小(大)则用变量k记住它在数组中的位置(下标),等到循环结束的时候,我们应该找到了最小(大)的那个数的下标了,然后进行判断,如果这个元素的下标不是第一个元素的下标,就让第一个元素跟他交换一下值,这样就找到整个数组中最小(大)的数了。然后找到数组中第二小(大)的数,让他跟数组中第二个元素交换一下值,以此类推。
2.运行过程:
(1)定义一个变量tmp记录待替换元素位置。
(2)比较待替换元素与当前元素的位置;若待替换元素大(小),则将tmp下标移到当前元素
(3)待替换元素与其后所有元素比较结束之后,交换待替换元素和tmp下标所记录的元素位置
(4)针对每一个元素重复以上操作,直到所有元素都有序。
3.算法实现(核心代码):
1 public static int[] selectionSort(int[] A) 2 for (int i = 0; i < A.length - 1; ++i) 3 int tmp = i; 4 for (int j = i + 1; j < A.length; ++j) 5 if (A[tmp] > A[j]) 6 tmp = j; 7 8 if (tmp != i) 9 int temp = A[tmp]; 10 A[tmp] = A[i]; 11 A[i] = temp; 12 13 14 return A; 15
三.插入排序(Insertion Sort):
1.基本思想:
每步将一个待排序的记录,按其关键码值的大小插入前面已经排序的元素中适当位置上,直到全部插入完为止。
2.运行过程:
(1)从第一个元素开始,该元素可以认为已经被排序。
(2)取出下一个元素,在已经排序的元素序列中从后向前扫描。
(3)如果该元素(已排序)大(小)于新元素,就将该元素移到下一位置。
(4)重复上述步骤,直到找到已排序元素小(大)于或等于新元素的位置。
(5)将新元素插入到下一位置中。
(6)重复上述步骤,直到所有元素有序。
3.算法实现(核心代码):
1 public static int[] insertionSort(int[] A, int n) 2 for (int i = 1; i < A.length; ++i) 3 int tmp = A[i]; 4 int j; 5 for (j = i - 1; j >= 0 && tmp < A[j]; --j) 6 A[j + 1] = A[j]; 7 8 A[j + 1] = tmp; 9 10 return A; 11
四.希尔排序(Shell’s Sort):
希尔排序是插入排序的一种又称“缩小增量排序”(Diminishing Increment Sort),是直接插入排序算法的一种更高效的改进版本。
1.基本思想:
先取一个小于n的整数d1作为第一个增量,把元素的全部记录分组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt−1…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。
2.运行过程:
(1)先取一个正整数d1<n,把所有序号相隔d1的数组元素放在一组,组内进行直接插入排序。
(2)然后取d2<d1,重复上述分组和排序操作。
(3)直到di=1,即所有记录放进一个组中排序为止。
3.算法实现(核心代码):
public static int[] shellSort(int[] A, int n)
for (int gap = n / 2; gap > 0; gap /= 2)
for (int i = gap; i < A.length; ++i)
for (int j = i - gap; j >= 0 && A[j] > A[j + gap]; j -= gap)
int tmp = A[j];
A[j] = A[j + gap];
A[j + gap] = tmp;
return A;
五.堆排序(Heapsort):
1.基本思想:
若以升序排序说明,把数组转换成最大堆积(Max-Heap Heap),这是一种满足最大堆积性质(Max-Heap Property)的二叉树:对于除了root之外的每个节点 i, A[parent(i)]≥A[i]。
重复从最大堆积取出数值最大的节点(把root节点和last节点 交换,把交换后的last节点移出堆),并让残余的堆积维持最大堆积性质。
2.运行过程:
(1)根据数组元素,建立最大(小)堆。
(2)取出最大(小)堆中的root节点与last?节点交换。
(3)调整恢复最大(小)堆。
(4)重复上述步骤,直至最大(小)堆中只有一个节点。
3.算法实现(核心代码):
1 public static int[] heapSort(int[] A, int n) 2 int beginIndex = n / 2; 3 //建堆 4 for (int i = beginIndex; i >= 0; --i) 5 maxHeapify(A, i, n); 6 7 for (int i = n - 1; i > 0; --i) 8 int tmp = A[0]; 9 A[0] = A[i]; 10 A[i] = tmp; 11 maxHeapify(A, 0, i); 12 13 return A; 14 15 private static void maxHeapify(int[] a, int i, int n) 16 int l = i * 2 + 1; 17 int r = i * 2 + 2; 18 int Max = i; 19 if (l < n && a[l] > a[Max]) 20 Max = l; 21 if (r < n && a[r] > a[Max]) 22 Max = r; 23 if (Max != i) 24 int tmp = a[Max]; 25 a[Max] = a[i]; 26 a[i] = tmp; 27 maxHeapify(a, Max, n); 28 29
六.归并排序(Merge Sort):
归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
1.基本思想:
将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
2.运行过程:
(1)申请空间,使其大小为两个已排序序列之和,该空间用来存放合并后的序列。
(2)设定两个指针,最初位置分别为两个已经排好序列的起始位置。
(3)比较两个指针所指向的元素,选择相对小(大)的元素放入合并空间,并移动指针到下一位置。
(4)重复上述操作,直到所有元素直接复制到合并序列尾。
3.算法实现(核心代码):
1 public static int[] mergeSort(int[] A, int n) 2 mergeSort_process(A, 0, A.length - 1); 3 return A; 4 5 private static void mergeSort_process(int[] a, int l, int r) 6 if (l == r) 7 return; 8 int mid = (l + r) / 2; 9 mergeSort_process(a, l, mid); 10 mergeSort_process(a, mid + 1, r); 11 merge(a, l, mid, r); 12 13 private static void merge(int[] a, int l, int mid, int r) 14 int[] tmp = new int[r - l + 1]; 15 int ll = l; 16 int rr = mid + 1; 17 int index = 0; 18 while (ll <= mid && rr <= r) 19 if (a[ll] <= a[rr]) 20 tmp[index++] = a[ll++]; 21 else 22 tmp[index++] = a[rr++]; 23 24 25 while (ll <= mid) 26 tmp[index++] = a[ll++]; 27 while (rr <= r) 28 tmp[index++] = a[rr++]; 29 for (int i = 0; i < tmp.length; ++i) 30 a[l + i] = tmp[i]; 31
七.快速排序(Quick Sort):
快速排序是对冒泡排序的一种改进。
1.基本思想:
通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
2.运行过程:
(1)从元素中任取一个数据作为关键数据(key)。
(2)所有小于key的元素,都移到key的左边;所有大于key的元素都移到key的右边。
(3)重复上述步骤,直到所有子集只剩下一个元素为止。
3.算法实现(核心代码):
1 public static int[] quickSort(int[] A, int n) 2 quickSort_process(A, 0, A.length - 1); 3 return A; 4 5 6 private static void quickSort_process(int[] a, int l, int r) 7 if (l > r) 8 return; 9 10 int tmp = a[l]; 11 int i = l; 12 int j = r; 13 while (i != j) 14 while (a[j] >= tmp && i < j) 15 --j; 16 17 while (a[i] <= tmp && i < j) 18 ++i; 19 20 if (i < j) 21 int temp = a[i]; 22 a[i] = a[j]; 23 a[j] = temp; 24 25 26 a[l] = a[i]; 27 a[i] = tmp; 28 29 quickSort_process(a, l, i - 1); 30 quickSort_process(a, i + 1, r); 31
八.计数排序(Counting Sort):
计数排序是一个非基于比较的排序算法,它的优势在于在对一定范围内的整数排序时,它的复杂度为O(n+k)(其中k是整数的范围),快于任何比较排序算法。但是这个是牺牲空间换取时间的做法。
1.基本思想:
(1)限制条件:输入的线性表的元素属于有限偏序集S
(2)思想:它创建一个长度为这个数据范围的数组,数组中每个元素记录要排序数组中对应记录的出现个数,最后再按照个数依次取出元素。
2.运行过程:
(1)找出待排序的数组中最大的元素,创建数组C(记录待排序数组中每个元素的个数,长度即为最大元素值)。
(2)统计数组中每个值为i的元素出现的次数,存入数组C的第i项。
(3)对所有的计数累加(从C?中的第一个元素开始,每一项和前一项相加)。
(4)反向填充目标数组:将每个元素i放在新数组的第C[i]项,每放一个元素就将C[i]减去1。
3.算法实现(核心代码):
1 public static int[] countingSort(int[] A, int n) 2 int Max = Arrays.stream(A).max().getAsInt(); 3 int mask[] = new int[Max + 1]; 4 for (int i = 0; i < A.length; ++i) 5 mask[A[i]] += 1; 6 7 for (int i = 0, j = 0; i < mask.length; ++i) 8 while (mask[i] > 0) 9 A[j++] = i; 10 mask[i] -= 1; 11 12 13 return A; 14
九.基数排序(Radix Sort):
1.基本思想:
将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。
2.运行过程:
(1)将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补0。
(2)从最低位开始,依次进行一次排序,排序之后,继续对排序之后的数组进行下一位排序。
(3)重复上面步骤,直至最高位排序完成之后。
3.算法实现(核心代码):
1 public static int[] radixSort(int[] A, int n) 2 int Max = Arrays.stream(A).max().getAsInt(); 3 for (int exp = 1; Max / exp > 0; exp *= 10) 4 count_sort(A, exp); 5 6 return A; 7 8 9 private static void count_sort(int[] a, int exp) 10 int output[] = new int[a.length]; 11 int mask[] = new int[10]; 12 for (int i = 0; i < a.length; ++i) 13 mask[(a[i] / exp) % 10]++; 14 15 for (int i = 1; i < mask.length; ++i) 16 mask[i] += mask[i - 1]; 17 18 for (int i = a.length - 1; i >= 0; --i) 19 output[--mask[(a[i] / exp) % 10]] = a[i]; 20 21 for (int i = 0; i < a.length; ++i) 22 a[i] = output[i]; 23 24
时间/空间复杂度、稳定性比较:
时间复杂度 | 空间复杂度 | 稳定性 | |
冒泡排序 | O(n^2) | O(1) | 稳定 |
选择排序 | O(n^2) | O(1) | 不稳定 |
插入排序 | O(n^2) | O(1) | 稳定 |
希尔排序 | O(n*logn) | O(1) | 不稳定 |
堆排序 | O(n*logn) | O(1) | 不稳定 |
归并排序 | O(n*logn) | O(N) | 稳定 |
快速排序 | O(n*logn) | O(logN)~O(n) | 不稳定 |
计数排序 | O(n) | O(m)(m为所选桶的数量) | 稳定 |
基数排序 | O(n) | O(m)(m为所选桶的数量) | 稳定 |
以上是关于排序总结的主要内容,如果未能解决你的问题,请参考以下文章