码迷,mamicode.com
首页 > 编程语言 > 详细

排序总结

时间:2019-09-12 09:23:47      阅读:82      评论:0      收藏:0      [点我收藏+]

标签:转换   循环   void   有序表   限制   缩小   ide   last   div   

一.冒泡排序(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为所选桶的数量) 稳定

排序总结

标签:转换   循环   void   有序表   限制   缩小   ide   last   div   

原文地址:https://www.cnblogs.com/Edviv/p/11509837.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!