排序算法(sorting)

对COMP20003中排序部分进行总结,图片来自COMP20003

有部分内容来自http://www.cnblogs.com/eniac12/p/5329396.html

演示动画:https://www.cs.usfca.edu/~galles/visualization/ComparisonSort.html



概念:

stable sort: 相同的值排序后相对顺序不变。

Comparison-based sorting is Ω(nlogn).



Hash function ---

用数对list中的元素求余,根据余值放入对应的桶(bucket)中,使用素数(prime)能使得分配更为均匀。

Collisions冲突:两个元素的余值相同时发生。当buckets数量<元素数量,则一定发生。1个好的hash function应尽量少出现collison,但不能认为collision不会发生,换言之要做好应对。

Collision Resolution Methods

  1.Chaining

最坏情况:所有值都在同一bucket,实际上为linked list。

2.Open addressing methods

    • Linear probing

当插入位置已有数据时,插入下一空余位置(循环),若全满了,则collision。

    • Double hashing

当插入位置已有数据时,进行第二次求余得出新的位置。注意第二次求余值要+1避免在仍在原地。



Distribution counting --- unusual approach to sorting

  计数排序(Counting sort):

requires: Key values to be within a certain range, lower to upper. 要排序的值在一定范围内。

通过记录所有数中,比该数小的有几个,来安排其位置。可以用辅助数组(auxiliary array)记录范围内比该值小(大)的有几个,也可以用for循环。用于整数排序。

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3
  4 int *countSort(int *n, int size);
  5 int *countSortIterative(int *n, int size);
  6 void printArray(int *n, int size);
  7 int min(int *n, int size);
  8 int max(int *n, int size);
  9
 10 int main(int argc, char **argv) {
 11     int size = 16;
 12     int unsortedArray[16] = {4,4,2,2,0,2,1,3,2,4,3,1,4,3,1,4};
 13     int *sortedArray = NULL;
 14     printArray(unsortedArray, size);
 15     //sortedArray = countSort(unsortedArray, size);
 16     sortedArray = countSortIterative(unsortedArray, size);
 17     printArray(sortedArray, size);
 18     free(sortedArray);
 19     return 0;
 20 }
 21
 22 void printArray(int *n, int size) {
 23     int i = 0;
 24     for (i = 0; i < size; i++) {
 25         printf("%d  ", n[i]);
 26     }
 27     printf("\n");
 28 }
 29
 30 int *countSortIterative(int *n, int size) {
 31     int i = 0, j = 0;
 32     int *sortedArray = NULL;
 33     int count = 0;
 34
 35     if((sortedArray = (int *) calloc(size, sizeof(int))) == NULL) {
 36         printf("calloc error\n");
 37         exit(EXIT_FAILURE);
 38     }
 39
 40     for (i = 0; i < size; i++) {
 41         for (j = 0, count = 0; j < size; j++) {
 42             if (i == j) {
 43                 continue;
 44             }
 45             if (n[i] > n[j]) {
 46                 count++;
 47             }
 48             if (i > j && n[i] == n[j]) {
 49                 count++;
 50             }
 51         }
 52         sortedArray[count] = n[i];
 53     }
 54     return sortedArray;
 55 }
 56
 57 int *countSort(int *n, int size) {
 58     int rangeFrom, rangeTo;
 59     int *cumulativeRecord = NULL;
 60     int *sortedArray = NULL;
 61     int i = 0;
 62
 63     rangeFrom = min(n, size);
 64     rangeTo = max(n, size);
 65     printf("size is %d, min is %d, max is %d\n", size, rangeFrom, rangeTo);
 66
 67     if((cumulativeRecord = (int *) calloc(rangeTo - rangeFrom + 1, sizeof(int))) == NULL) {
 68         printf("calloc error\n");
 69         exit(EXIT_FAILURE);
 70     }
 71     for (i = 0; i < size; i++) {
 72         cumulativeRecord[n[i] - rangeFrom]++;
 73     }
 74     for(i = 0; i < rangeTo - rangeFrom + 1; i++) {
 75         if (i == 0) {
 76             continue;
 77         }
 78         cumulativeRecord[i] = cumulativeRecord[i] + cumulativeRecord[i - 1];
 79     }
 80     //printArray(cumulativeRecord, rangeTo - rangeFrom + 1);
 81     if((sortedArray = (int *)malloc(size * sizeof(int))) == NULL) {
 82         printf("malloc error\n");
 83         exit(EXIT_FAILURE);
 84     }
 85
 86     for ( i = 0; i < size; i++) {
 87         sortedArray[cumulativeRecord[n[i] - rangeFrom]-1] = n[i];
 88         cumulativeRecord[n[i] - rangeFrom] --;
 89     }
 90     //printArray(sortedArray, size);
 91     free(cumulativeRecord);
 92     return sortedArray;
 93 }
 94
 95 int min(int *n, int size) {
 96     int i = 0;
 97     int min = n[0];
 98     for (i = 1; i < size; i++) {
 99         if (min > n[i]) {
100             min = n[i];
101         }
102     }
103     return min;
104 }
105 int max(int *n, int size) {
106     int i = 0;
107     int max = n[0];
108     for (i = 1; i < size; i++) {
109         if (max < n[i]) {
110             max = n[i];
111         }
112     }
113     return max;
114 }

复杂度:O(n)   (non-comparison-based)



选择排序Selection sort

选择排序是一种简单直观的排序算法。它的工作原理很容易理解:初始时在序列中找到最小(大)元素,放到序列的起始位置作为已排序序列;然后,再从剩余未排序元素中继续寻找最小(大)元素,放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

  注意选择排序与冒泡排序的区别:冒泡排序通过依次交换相邻两个顺序不合法的元素位置,从而将当前最小(大)元素放到合适的位置;而选择排序每遍历一次都记住了当前最小(大)元素的位置,最后仅需一次交换操作即可将其放到合适的位置。

worst case: O(n^2)
best case: O(n^2)
average case: O(n^2)
unstable sort:

  选择排序是不稳定的排序算法,不稳定发生在最小元素与A[i]交换的时刻。

  比如序列:{ 5, 8, 5, 2, 9 },一次选择的最小元素是2,然后把2和第一个5进行交换,从而改变了两个元素5的相对次序。

 1 #include <stdio.h>
 2
 3 /* sort the array from min to max
 4     worst case: O(n^2)
 5     best case: O(n^2)
 6     average case: O(n^2)
 7     unstable sort
 8 */
 9 void selectionSort(int *array, int size);
10 void swap(int *array, int a, int b);
11 void printArray(int *n, int size);
12
13 int main(int argc, char **argv) {
14     int array[10] = {10,9,7,8,6,5,4,3,2,1};
15     printArray(array, 10);
16     selectionSort(array, 10);
17     printArray(array, 10);
18     return 0;
19 }
20
21 /* sort the array from min to max */
22 void selectionSort(int *array, int size) {
23     int i, j, min;
24
25     for (i = 0; i < size - 1; i++) {
26         min = i;
27         for (j = i + 1; j < size; j++) {
28             if (array[min] > array[j]) {
29                 min = j;
30             }
31         }
32         if (i != min) {
33             swap(array, i, min);
34         }
35     }
36 }
37
38 void swap(int *array, int a, int b) {
39     int temp = array[a];
40     array[a] = array[b];
41     array[b] = temp;
42 }
43
44 void printArray(int *n, int size) {
45     int i = 0;
46     for (i = 0; i < size; i++) {
47         printf("%d  ", n[i]);
48     }
49     printf("\n");
50 }



插入排序Insertion sort

  类似于打扑克时抽牌时的操作,抽到第n张时,与前一张比较大小,直到前一张的牌比第n张小,则插入此位置。

worst case O(n^2)
average case O(n^2)
best case O(n): 当list已经拍好顺序时。
stable sort

 1 #include <stdio.h>
 2 /* sort the array from min to max
 3     worst case O(n^2)
 4     average case O(n^2)
 5     best case O(n)
 6     stable sort
 7 */
 8 void insertionSort(int *array, int size);
 9 void printArray(int *n, int size);
10
11 int main(int argc, char **argv) {
12     int array[10] = {-9, 10, 2, 3, -4, 4, 8, 12, 15, 7};
13     printArray(array, 10);
14     insertionSort(array, 10);
15     printArray(array, 10);
16     return 0;
17 }
18
19 void insertionSort(int *array, int size) {
20     int i = 1, j, insertionVal;
21     for (i = 1; i < size; i++) {
22         insertionVal = array[i];
23         j = i;
24         while( j - 1 >= 0 && array[j - 1] > insertionVal) {
25             array[j] = array[j - 1];
26             j--;
27         }
28         array[j] = insertionVal;
29     }
30 }
31
32 void printArray(int *n, int size) {
33     int i = 0;
34     for (i = 0; i < size; i++) {
35         printf("%d  ", n[i]);
36     }
37     printf("\n");
38 }



分治策略(divide-and-conquer sorting algorithm):

快速排序(Quicksort)---Hard split, easy join:

  Partition array:

Pick Pivot, which it is in its final position

Everything larger than pivot has higher index

Everything less than pivot has lower index

选择一个pivot枢纽(?不知道中文该对应哪个),可以是最左边或最右边等由自己决定,根据pivot的选择不同,会有不同效果。比pivot大的排在pivot右边,小的排在左边,只是如此,在左边的和右边的序列并未按序。

Recursion:

Partition left-half(recursively)

Partition right-half(recursively)

Base case:singletons are already sorted

如此不断递归。

注意:在选择pivot时,最后将pivot放置到正确位置,如选择最左作为pivot,在partition时,最后将从右开始筛选的替换。

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3
 4 void quicksort(int *n, int l, int r);
 5 void printArray(int *n, int i);
 6 int partition(int *n, int l, int r);
 7 int partitionLeft(int *n, int l, int r);
 8 int partitionRight(int *n, int l, int r);
 9 void swap(int *n, int i, int j);
10
11 int main(int argc, char **argv) {
12     int *n = (int *) malloc(sizeof(int));
13     int i = 0;
14     int data;
15     while (scanf("%d", &data) == 1) {
16         n = realloc(n, sizeof(int) * (i + 1));
17         n[i] = data;
18         i++;
19     }
20     printArray(n, i);
21     quicksort(n, 0, i - 1);
22
23     printArray(n, i);
24     free(n);
25     return 0;
26 }
27
28 void printArray(int *n, int i) {
29     int j = 0;
30     for (j = 0; j < i; j++) {
31         printf("%d   ", n[j]);
32     }
33     printf("\n");
34 }
35
36 void quicksort(int *n, int l, int r) {
37     int i;
38     if (l >= r) {
39         return;
40     }
41     i = partition(n, l, r);
42     quicksort(n, l, i - 1);
43     quicksort(n, i + 1, r);
44 }
45
46 int partition(int *n, int l, int r) {
47     return partitionLeft(n, l, r);
48     //return partitionRight(n, l, r);
49 }
50
51 int partitionLeft(int *n, int l, int r) {
52     int pivot = n[l];
53     int left = l;
54     int right = r + 1;
55     while(1) {
56         do{
57             left++;
58         } while(n[left] < pivot);
59         do{
60             right--;
61         } while(n[right] > pivot);
62
63         if (left >= right) {
64             break;
65         }
66         swap(n, left, right);
67     }
68     swap(n, l, right);
69     return right;
70 }
71
72 int partitionRight(int *n, int l, int r) {
73     int pivot = n[r];
74     int left = l - 1;
75     int right = r;
76     while(1) {
77         do{
78             left++;
79         } while(n[left] < pivot);
80         do{
81             right--;
82         } while(n[right] > pivot);
83
84         if (left >= right) {
85             break;
86         }
87         swap(n, left, right);
88     }
89     swap(n, r, left);
90     return left;
91 }
92
93 void swap(int *n, int i, int j) {
94     int temp = n[i];
95     n[i] = n[j];
96     n[j] = temp;
97 }

归并排序(Mergesort)---Easy split, hard join:

关键:当有两个已排好顺序的list(array or linked list)要合并(merge)成一个时,使用两个指针分别指向两个lists,比较其大小,小的放入新list,其对应指针指向下一个,直到两个lists都装入新list。

 1 /* merge two sorted arrays, first -- mid, mid + 1 -- last  */
 2 void merge(int *array, int first, int mid, int last) {
 3     int newArray[last - first + 1];
 4     int i, j, k;
 5     for (i = first, j = mid + 1, k = 0; k < last - first + 1; k++) {
 6         if (i > mid) {
 7             newArray[k] = array[j++];
 8             continue;
 9         }
10         if (j > last) {
11             newArray[k] = array[i++];
12             continue;
13         }
14         if (array[i] < array[j]) {
15             newArray[k] = array[i++];
16         } else {
17             newArray[k] = array[j++];
18         }
19     }
20
21     /* paste newArray to array */
22     for (i = first, k = 0; i <= last ; i++, k++) {
23         array[i] = newArray[k];
24     }
25 }

分为两种:1.Top-down mergesort(recursive)

将list不断一分为二,直到分成单个为止,然后开始合并,使用递归。

 1 void mergeSortRecursion(int *array, int first, int last) {
 2     int mid = (first + last) / 2;
 3
 4     if (first == last) {
 5         return;
 6     }
 7     mergeSortRecursion(array, first, mid);
 8     mergeSortRecursion(array, mid + 1, last);
 9     merge(array, first, mid, last);
10 }

     2.Bottom-up mergesort(iterative)

将list看作是由单个元素的lists组成的,两两合并,使用迭代。

 1 void mergeSortIterative(int *array, int len) {
 2     int i, first, mid, last;
 3     for (i = 1; i < len; i *= 2) {
 4         first = 0;
 5         while(first + i < len) {
 6             mid = first + i - 1;
 7             last = mid + i < len ? mid + i : len - 1;
 8             merge(array, first, mid, last);
 9             printf("first = %d, mid = %d, last = %d\n", first, mid, last);
10             first = last + 1;
11         }
12         printArray(array, len);
13     }
14 }

原文地址:https://www.cnblogs.com/Will-zyq/p/10077548.html

时间: 2024-10-04 22:32:32

排序算法(sorting)的相关文章

第23章 排序算法(包括merge等)

  第23章 排序算法  Sorting:1 sort Sort elements in range (function template)2 stable_sort Sort elements preserving order of equivalents (function template)3 partial_sort Partially Sort elements in range (function template)4 partial_sort_copy Copy and parti

Collection of algorithm for sorting. 常见排序算法集(一)

Collection of algorithm for sorting (part one) 选择排序--Selection sort 可能你会觉得奇怪,为什么用结构体传参? 那是一层封装,我在面向对象的思想来写 : ) 对已一个数组,不管怎么操作,都不能越界. C语言 不会自动检查数组越界.这个时候程序员就应该负起责任来. 数组的边界成为数组必不可少的信息,此时可以把array当作一个对象来看,即此时的element. 我们排序的对象可能会变,比方说从int类型变到char类型,这时候我们仅仅

经典排序算法 - 耐心排序Patience Sorting

经典排序算法 - 耐心排序Patience Sorting 这个排序的关键在建桶和入桶规则上 建桶规则:如果没有桶,新建一个桶;如果不符合入桶规则那么新建一个桶 入桶规则:只要比桶里最上边的数字小即可入桶,如果有多个桶可入,那么按照从左到右的顺序入桶即可 举个例子,待排数组[6 4 5 1 8 7 2 3] 第一步,取数字6出来,此时一个桶没有,根据建桶规则1新建桶,将把自己放进去,为了表述方便该桶命名为桶1或者1号桶 第二步,取数字4出来,由于4符合桶1的入桶规则,所以入桶1,并放置在6上边,

排序(Sorting)算法的比较与选择

之前的博客已经介绍过各种排序算法的基本介绍,详情见:Python数据结构应用5--排序(Sorting).由于找工作需要,这里总结了一下这些排序算法的区别与选择依据. 影响排序的因素有很多,平均时间复杂度低的算法并不一定就是最优的.相反,有时平均时间复杂度高的算法可能更适合某些特殊情况.一般而言,需要考虑的因素有以下几点: 1.待排序的记录数目n的大小: 2.数据的预先分布情况: 3.对排序稳定性的要求. Reference: https://blog.csdn.net/FISHBALL1/ar

普林斯顿大学算法课 Algorithm Part I Week 3 排序算法复杂度 Sorting Complexity

计算复杂度(Computational complexity):用于研究解决特定问题X的算法效率的框架 计算模型(Model of computation):可允许的操作(Allowable operations) 成本模型(Cost model):操作数(Operation counts) 上界(Upper bound):最多的成本 下界(Lower bound):最少的成本 最优算法(Optimal algorithm):最有可能性的成本的算法(Algorithm with best pos

查找与排序算法(Searching adn Sorting)

1,查找算法 常用的查找算法包括顺序查找,二分查找和哈希查找. 1.1 顺序查找(Sequential search) 顺序查找: 依次遍历列表中每一个元素,查看是否为目标元素.python实现代码如下: #无序列表 def sequentialSearch(alist,item): found = False pos=0 while not found and pos<len(alist): if alist[pos]==item: found=True else: pos = pos+1 r

经典排序算法

经典排序算法(via  kkun) 经典排序算法,以下文章参考了大量网上的资料,大部分都给出了出处 这一系列重点在理解,所以例子什么的都是最简单的情况,难免失误之处,多指教 大多数排序算法都给出了每一步的状态,以方便初学者更容易理解,通俗易懂,部分难以理解的排序算法则给出了大量的图示,也算是一个特色吧 经典排序算法 - 快速排序Quick sort 经典排序算法 - 桶排序Bucket sort 经典排序算法 -  插入排序Insertion sort 经典排序算法 - 基数排序Radix so

模板化的七种排序算法,适用于T* vector&lt;T&gt;以及list&lt;T&gt;

最近在写一些数据结构以及算法相关的代码,比如常用排序算法以及具有启发能力的智能算法.为了能够让写下的代码下次还能够被复用,直接将代码编写成类模板成员函数的方式,之所以没有将这种方式改成更方便的函数模板纯属于偷懒,更方便于测试代码的有效性,等代码写完也懒得去改了.下面开始介绍这段代码,有什么不对的地方欢迎前来指正. 一共写了七种排序,插入排序InsertSort.堆排序HeapSort.快速排序QuickSort.合并排序MergeSort,计数排序CountingSort,基数排序RadixSo

总结: Sort 排序算法

排序总结 面试经验 硅谷某前沿小Startup面试时,问到的一个题目就是写一个快速排序算法.进而面试官问到了各种算法的算法复杂度,进而又问了Merge Sort 与 QuickSort 的优劣. 对排序算法的全面理解,体现了计算机学生的功底. 现在来讲Merge Sort 与Quick Sort 是最流行的算法,以下我们来一步一步地分析: SORT分类 在计算机科学所使用的排序算法通常被分類為: 計算的時間複雜度(最差.平均.和最好表現),依據串列(list)的大小(n).一般而言,好的表現是O