算法 十大基本排序算法

1. 优化冒泡排序 O(n2)

算法描述:两两比较,将较小的数字置前,逐一替换;

算法优化点:使用flag来判断是否使用了swap交换,若本身有序则直接break;

算法分析:稳定,但慢,每次只能移动相邻两个数据。

动图演示:

冒泡排序

代码:

 1 void bubble_sort(vector  <int> &q){
 2     for ( int i = q.size() - 1; i > 0; i --){
 3         bool flag = false;
 4         for ( int j = 0; j + 1 <= i; j ++)
 5             if ( q[j] > q[j + 1]){
 6                 swap(q[j], q[j + 1]);
 7                 flag = true;
 8             }
 9         if (!flag) break;
10     }
11 }

2. 选择排序 O(n2)

算法描述:从头开始,选择无序区最小的数置入有序区;

算法分析:表现稳定,不占用额外内存空间,但比较次数多。

动图演示:

选择排序

代码:

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

3. 插入排序 O(n2)

算法描述:取出扫描元素与有序区比较,将小于数置后,按位移动;

算法分析:稳定,快,但比较次数不一定,比较次数越少,插入点后的数据移动越多,特别是当数据总量庞大的时候,但用链表可以解决。

动图演示:

代码:

 1 void insertion_sort(vector<int> &q){
 2     for ( int i = 1; i < q.size(); i ++){
 3         int t = q[i], j;
 4         for( j = i - 1; j >= 0; j --){
 5             if( t < q[j] ) q[j + 1] = q[j];
 6             else break;
 7         }
 8         q[j + 1] = t;
 9     }
10  }

4. 希尔排序 O(n1.3)

算法描述:首先取一增量d(d<n),将a[1]、a[1+d]、a[1+2d]……列为第一组,a[2]、a[2+d]、 a[2+2d]……列为第二组……,a[d]、a[2d]、a[3d]……列为最后一组以次类推,在各组内用插入排序,然后取d'<d,重复上述操 作,直到d=1。

算法分析:快,数据移动少,但不稳定,d的取值是多少,应取多少个不同的值,都无法确切直达,只能凭经验来取。

动图演示:

5. 归并排序 O(nlog2n)

算法描述:将一个数组分为两部分,进行分别排序,后再相互比较,得出最终有序数组。

算法分析:快,无论情况如何,时间复杂度均是O(nlog2n),但若数据节点数据量大,则不合适。

动图演示:

代码:

 1  void merge_sort(vector<int> &q, int l, int r){
 2     if (l >= r) return;
 3     
 4     int mid = (l + r) >> 1;
 5     merge_sort(q, l, mid);
 6     merge_sort(q, mid + 1, r);
 7     
 8     static vector<int> w;
 9     w.clear();
10     
11     int i = l, j = mid + 1;
12     while (i <= mid && j <= r)
13         if(q[i] <= q[j]) w.push_back(q[i ++]);
14         else w.push_back(q[j ++]);
15         
16     while (i <= mid) w.push_back(q[i ++]);
17     while (j <= r) w.push_back(q[j ++]);
18     
19     for(i = l, j = 0; j < w.size(); i ++, j ++) q[i] = w[j];
20  }

6. 快速排序 O(nlog2n)

算法描述:选择一个基准,将较小的放置左边,大的放置右边,再使用递归把小雨的子数列和大于的子数列进行排序。

算法分析:不稳定快,数据移动少,但不稳定

动图演示:

代码:

 1 void quick_sort(vector<int> &q, int l, int r){
 2      if (l >= r) return;
 3      int i = l - 1, j= r + 1, x = q[l + r >> 1];
 4      while(i < j){
 5          do j --; while (q[j] > x);
 6          do i ++; while (q[i] < x);
 7          if (i < j) swap(q[i],q[j]);
 8          else quick_sort(q, l, j), quick_sort(q, j + 1, r);
 9      }
10  }

7. 堆排序 O(nlog2n)

算法描述:将初始待排序序列(R1,R2….Rn)构建成大顶堆,将堆顶元素R(1)与末尾元素R(n)交换,将其置入有序区,后再将新堆(R1,R2….Rn-1)调整为大顶堆,后再重复上述步骤,直至有序区元素个数为n-1.

算法分析:不稳定,复杂。

动图演示:

8. 计数排序 O(n+k)

算法描述:将无序数组中的每个数 i 都放入数组C[ i ]中,并对所有数字进行累加,后从数组中按序输出。

算法分析:稳定,时间快。适用于k不是很大且比较集中。

动图演示:

9. 桶排序 O(n)

算法描述:设置一个定量的数组当作空桶;便理输入数据,并发数据一个一个放入桶中,对每个非空桶进行排序,并完成拼接。

算法分析:最好情况下使用线性时间O(n),桶排序的时间复杂度,取决与对各个桶之间数据进行排序的时间复杂度,显然,桶划分越小,各个桶之间的数据越少,排序越快,但相应的空间消耗会增大。

图片演示:

10. 基数排序 O(n+k)

算法描述:先取得数组中的最大数,并取得位数,后使原始数组从最低位取每个位组成的radix数组,并对radix进行计数排序。

算法分析:基数排序基于分别排序,分别收集,所以是稳定的。但基数排序的性能比桶排序要略差,每一次关键字的桶分配都需要O(n)的时间复杂度,而且分配之后得到新的关键字序列又需要O(n)的时间复杂度。假如待排数据可以分为d个关键字,则基数排序的时间复杂度将是O(d*2n) ,当然d要远远小于n,因此基本上还是线性级别的。基数排序的空间复杂度为O(n+k),其中k为桶的数量。一般来说n>>k,因此额外空间需要大概n个左右。

动图演示:

部分内容及动画演示参考:https://www.cnblogs.com/onepixel/articles/7674659.html

猜你喜欢

转载自www.cnblogs.com/john1015/p/12904858.html