排序算法总结

冒泡排序:从无序区通过交换找出最大元素放到有序区前端。

1 void BubbleSort(vector<int> &v) {
2     int n = v.size();
3     for (int i = 0; i < n - 1; ++i)
4         for (int j = 0; j < n - 1 - i; ++j)
5             if (v[j] > v[j + 1])
6                 swap(v[j], v[j + 1]);
7 }

选择排序:从未排序序列中找到最小(大)元素,存到已排序序列的起始位置。

 1 void SelectSort(vector<int> &v) {
 2     int n = v.size();
 3     for (int i = 0; i < n - 1; ++i) {
 4         min = i;
 5         for (int j = i + 1; j < n; ++j) {
 6             if (v[j] < v[min]) 
 7                 min = j;
 8         }
 9         if (i != min)
10             swap(v[j], v[min]);
11     }
12 }

插入排序:

1. 从第一个元素开始,该元素可以认为已经被排序

2. 取出下一个元素,在已经排序的元素序列中从后向前扫描

3. 如果该元素(已排序)大于新元素,将该元素移到下一位置

4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置

5. 将新元素插入到该位置后

6. 重复步骤2~5

 1 void InsertSort(vector<int> &v) {
 2     int n = v.size();
 3     for (int i = 1; i < n; ++i) {
 4         int tmp = v[i];
 5         for (int j = i - 1; j >= 0; --j) {
 6             if (v[j] > tmp) {
 7                 v[j + 1] = v[j];
 8                 v[j] = tmp;
 9             } else break;
10         }
11     }
12 }

快速排序:(小数,基准元素,大数)。在区间中随机挑选一个元素作基准,将小于基准的元素放在基准之前,大于基准的元素放在基准之后,再分别对小数区与大数区进行排序。

 1 void QuickSort(vector<int> &v, int left, int right) {
 2     if (left >= right) return;
 3     int i = left + 1, j = right, key = v[left];
 4     while (i < j) {
 5         while (v[i] < key)
 6             i++;
 7         while (v[j] > key)
 8             j--;
 9         if (i < j)
10             swap(v[i++], v[j--]);
11         else i++;
12     }
13     swap(v[j], v[left]);
14     QuickSort(v, left, j - 1);
15     QuickSort(v, j + 1, right);
16 }

归并排序:归并排序是将数组分成两半,这两半分别排序后,再归并在一起。排序某一半时,继续沿用
同样的排序算法,最终,你将归并两个只含一个元素的数组。

 1 void Merge(vector<int> &v, int left, int mid, int right) {
 2     int i = left, j = mid + 1;
 3     vector<int> help(right - left + 1, 0);
 4     for (int k = 0; k < right - left; ++k) 
 5         help[k] = v[left + k];
 6     for (int k = 0; k < rigfht - left; ++k) {
 7         if (i > mid) v[left + k] = help[j++];
 8         else if (j > right) v[lqft + k] = help[i++];
 9         else if (help[j - left] < help[i - left]) v[left + k] = help[j++ - left];
10         else v[left + k] = help[i++ - left];
11     }
12 }
13 void MergeSort(vector<int> &v, int l, int r) {
14     if (r <= l) return;
15     int mid = l + (r - l) / 2;
16     MergeSort(v, l, mid);
17     MergeSort(v, mid + 1, r);
18     merge(v, l, mid, r);
19 }

希尔排序:每一轮按照事先决定的间隔进行插入排序,间隔会依次缩小,最后一次一定要是1。

 1 void ShellSort(vector<int> &v, int length) {
 2     int h = 1;
 3     while (h < length / 3) {
 4         h = 3 * h + 1;
 5     }
 6     while (h >= 1) {
 7         for (int i = h; i < length; i++) {
 8             for (int j = i; j >= h && v[j] < v[j - h]; j -= h) {
 9                 swap(a[j], a[j - h]);
10             }
11         }
12         h = h / 3;
13     }
14 }

非比较排序算法:

堆排序:堆是一种特殊的树形数据结构,即完全二叉树。堆分为大根堆和小根堆,大根堆为根节点的值大于两个子节点的值;小根堆为根节点的值小于两个子节点的值,同时根节点的两个子树也分别是一个堆。

  • 步骤一:建立大根堆--将n个元素组成的无序序列构建一个大根堆,
  • 步骤二:交换堆元素--交换堆尾元素和堆首元素,使堆尾元素为最大元素;
  • 步骤三:重建大根堆--将前n-1个元素组成的无序序列调整为大根堆

    重复执行步骤二和步骤三,直到整个序列有序。

 

计数排序:计数排序基于一个假设,待排序数列的所有数均为整数,且出现在(0,k)的区间之内。如果 k(待排数组的最大值) 过大则会引起较大的空间复杂度,一般是用来排序 0 到 100 之间的数字的最好的算法,但是它不适合按字母顺序排序人名。计数排序不是比较排序,排序的速度快于任何比较排序算法。时间复杂度为 O(n+k),空间复杂度为 O(n+k)。

 

 桶排序:

  1. 将待排序元素划分到不同的桶。先扫描一遍序列求出最大值 maxV 和最小值 minV ,设桶的个数为 k ,则把区间 [minV, maxV] 均匀划分成 k 个区间,每个区间就是一个桶。将序列中的元素分配到各自的桶。
  2. 对每个桶内的元素进行排序。可以选择任意一种排序算法。
  3. 将各个桶中的元素合并成一个大的有序序列。
  4. 假设数据是均匀分布的,则每个桶的元素平均个数为 n/k 。假设选择用快速排序对每个桶内的元素进行排序,那么每次排序的时间复杂度为 O(n/klog(n/k)) 。总的时间复杂度为 O(n)+O(m)O(n/klog(n/k)) = O(n+nlog(n/k)) = O(n+nlogn-nlogk 。当 k 接近于 n 时,桶排序的时间复杂度就可以金斯认为是 O(n) 的。即桶越多,时间效率就越高,而桶越多,空间就越大

基数排序:

1. 将所有待排序整数(注意,必须是非负整数)统一为位数相同的整数,位数较少的前面补零
2. 从最低位开始,依次进行一次稳定排序。这样从最低位一直到最高位排序完成以后,整个序列就变成了一个有序序列。

为什么同一数位的排序子程序要用稳定排序?因为稳定排序能将上一次排序的成果保留下来。

排序算法 平均时间复杂度 最差时间复杂度 空间复杂度 稳定性 适用场景
冒泡排序 O(n2) O(n2) O(1) 稳定  
选择排序 O(n2) O(n2) O(1) 数据不稳定,链表稳定  
插入排序 O(n2) O(n2) O(1) 稳定 不适合对于数据量比较大的排序应用
快速排序 O(nlog2n) O(n2) O(log2n) 不稳定  
归并排序 O(nlog2n) O(nlog2n) O(n) 稳定  
希尔排序 O(nlog2n) O(n2) O(1) 不稳定  
堆排序 O(nlog2n) O(nlog2n) O(1) 不稳定  
计数排序 O(n+m) O(n+m) O(n+m) 稳定 最大值和最小值差距尽可能小
桶排序 O(n) O(n) O(m) 稳定 元素尽可能均匀分布
基数排序 O(kn) O(n2)   稳定 非负整数,最大值和最小值的差距尽可能小

其中m代表数据最大值减去最小值。

posted @ 2019-07-22 22:33  ppwq  阅读(165)  评论(0编辑  收藏  举报