数据结构与算法之十大排序

转载:https://blog.csdn.net/zhangshk_/article/details/82911093

01 术语:

  • 稳定:假设排序前a在b前面且a=b,那么排序后a仍然在b前面,即排序过程中不会出现跳跃式交换数据,只能相邻的才交换数据;
  • 不稳定:和上面相反;
  • 内排序:比较排序,即所有的排序操作均在内存中完成,比如冒泡、选择、插入、希尔、堆、快排、归并;
  • 外排序:非比较排序,即数据量太大,需要借助于磁盘来存储数据,比如计数、基数、桶;
  • 时间复杂度:耗费的时间级别,比如O(lgN), O(N),O(NlgN),O(N^2)等;
  • 空间复杂度:所需内存的大小,比如O(lgN), O(N),O(NlgN),O(N^2)等;

02 十大排序算法总结:

 1. 冒泡排序

  • 依次比较相邻两个元素,如果前面>后面则交换;
  • 第一轮比较完成后,最大的元素排在了最后面;
  • 重复步骤1-2,N-1轮遍历后则排序完成;

时间复杂度:O(N)~O(N^2),平均O(N^2);当元素基本有序时复杂度最好即O(N);

 1 void bubble_sort(int arr[], int len)
 2 {
 3     bool is_exchange = false;
 4     if(NULL == arr || len <= 1)
 5     {
 6         return ;
 7     }
 8 
 9     for(int i = 0; i < len-1; i++)
10     {
11         is_exchange = false;
12         for(int j = 0; j < len-i-1; j++)
13         {
14             if(arr[j] > arr[j+1])
15             {
16                 swap(&arr[j], &arr[j+1]);
17                 is_exchange = true;
18             }
19         }
20         //not exhcange, it indicate that the rest of arr is sorted, so jump and sort has been completed.
21         if(false == is_exchange)
22         {
23             break;
24         }
25     }
26 }
View Code

2. 选择排序

  • 第i轮遍历时,初始化minIndex=i,遍历N-i次寻找到最小数据的索引为k
  • 交换minIndex和k对应的数据后,那么位置i上就是本轮遍历的最小数据;
  • 重复1-2,N-1轮遍历后则排序完成;

时间复杂度:O(N^2);

 1 void select_sort(int arr[], int len)
 2 {
 3     int min = 0;
 4     if(NULL == arr || len <= 1)
 5     {
 6         return ;
 7     }
 8 
 9     for(int i = 0; i < len-1; i++)
10     {
11         min = i;
12         for(int j = i+1; j < len; j++)
13         {
14             if(arr[j] < arr[min])
15             {
16                 min = j;
17             }
18         }
19         if(min != i)
20         {
21             swap(&arr[min], &arr[i]);
22         }
23     }
24 }
View Code

3. 插入排序

  • 进行第i轮遍历,此时前面i-1个数据已经排好序;
  • 取出元素a[i],依次和前面的元素比较,找到比a[i]大的最小元素,假设下标是j,那么a[j-1] < a[i] < a[j];
  • 将元素a[i]插入到a[j-1]和a[j]中间;
  • 重复步骤1-3,N-1轮遍历后则排序完成;

时间复杂度:O(N)~O(N^2),平均O(N^2);当元素基本有序时复杂度最好即O(N);

 1 void insert_sort(int arr[], int len)
 2 {
 3     int value = 0, j = 0;
 4     if(NULL == arr || len <= 1)
 5     {
 6         return ;
 7     }
 8 
 9     for(int i = 1; i < len; i++)
10     {
11         value = arr[i];
12         for(j = i-1; j >= 0 && arr[j] > value; j--)
13         {
14             arr[j+1] = arr[j];
15         }
16         arr[j+1] = value;
17     }
18 }
View Code

4.希尔排序---升级版的插入排序

  • 选择一个递减的增量序列,t1,t2,……tk,且tk=1;
  • 假设增量为gap,即把排序元素分为gap组,同事对gap组进行插入排序
  • 重复步骤1-2,gap逐级递减,当gap=1时完全等同于插入排序,则排序完成

时间复杂度:O(NlogNloN)???

 1 void shell_sort(int arr[], int len)
 2 {
 3     int gap = len, value = 0, j = 0;
 4     if(NULL == arr || len <= 1)
 5     {
 6         return ;
 7     }
 8 
 9     while(gap > 1)
10     {
11         gap = gap/3 + 1;
12         for(int i = gap; i < len; i++)
13         {
14             value = arr[i];
15             for(j = i-gap; j >= 0 && arr[j] > value; j -= gap)
16             {
17                 arr[j+gap] = arr[j];
18             } 
19             arr[j+gap] = value;
20         }
21     }
22 }
View Code

5.堆排序---升级版的选择排序

堆是一种完全二叉树的数据结构,任意一节点的value都大于(小于)它的孩子节点的value;

  • 构建最大堆;
  • 将堆顶元素和最后一个元素交换,那么最后一个元素为最大值;
  • 交换堆顶后可能会违反堆的性质,需要从堆顶开始递归和孩子节点比较,重新构建最大堆
  • 重复步骤1-3,则排序完成

时间复杂度:O(NlgN);

 1 void adjust_max_heap(int arr[], int len, int cur)
 2 {
 3     int child = 0;
 4     if(NULL == arr || len <= 1 || cur >= len)
 5     {
 6         return ;
 7     }
 8 
 9     while(2*cur + 1 < len) //exist left child
10     {
11         child = 2*cur + 1;//left node
12         if(child+1 < len && arr[child] < arr[child+1]) //exist right child and left child < right child
13         {
14             child++;
15         }
16 
17         if(arr[cur] < arr[child])
18         {
19             swap(&arr[cur], &arr[child]);
20             cur = child;
21         }
22         else
23         {
24             break;
25         }
26     }
27 }
28 
29 void heap_sort(int arr[], int len)
30 {
31     if(NULL == arr || len <= 1)
32     {
33         return ;
34     }
35 
36     //1.build max_heap
37     for(int i = len/2-1; i >= 0; i--)
38     {
39         adjust_max_heap(arr, len, i);
40     }
41 
42     //2.exchange front and back, adjust the reset of heap to max_heap
43     for(int j = len-1; j >= 1; j--)
44     {
45         swap(&arr[j], &arr[0]);
46         adjust_max_heap(arr, j, 0);
47     }
48 }
View Code

6. 快速排序---升级版的冒泡

  • partition即从初始序列中挑选一个基准pivot,使得位于pivot之前的元素都小于pivot,位于pivot之后的元素都大于pivot;
  • 递归操作pivot的前部分;
  • 递归操作pivot的后部分;

时间复杂度:O(NlgN)~O(N^2),平均O(NlgN);当元素有序后倒序时复杂度最差即O(N^2);

 1 int partition(int arr[], int low, int high)
 2 {
 3     int pivot = low, val = 0;
 4     if(NULL == arr || low >= high)
 5     {
 6         return low;
 7     }
 8 
 9     val = arr[low];
10     while (low < high)  //low<high, not include "="
11     {
12         while(low < high && arr[high] >= val)  //low<high, not include "="
13         {
14             high--;
15         }
16         //swap(&arr[low], &arr[high]);
17 
18         while(low < high && arr[low] <= val)  //low<high, not include "="
19         {
20             low++;
21         }
22         swap(&arr[low], &arr[high]);
23     }
24     //this moment, low equal high, maybe not equal index !!!!!!
25     swap(&arr[low], &arr[pivot]);
26     return low;
27 
28 }
29 void _qsort(int arr[], int low, int high)
30 {
31     int pivot = 0;
32     if(low >= high)
33     {
34         return ;
35     }
36 
37     pivot = partition(arr, low, high);
38     _qsort(arr, 0, pivot -1);
39     _qsort(arr, pivot + 1, high);
40 }
41 
42 void quick_sort(int arr[], int len)
43 {
44     if(NULL == arr || len <= 1)
45     {
46         return ;
47     }
48 
49     _qsort(arr, 0, len-1);
50 
51 }
View Code

7. 归并排序

  • 将长度为n的初始序列分为两个长度为n/2的子序列;
  • 递归对两个子序列排序;
  • 将两个排好序的子序列合并为一个最终的排序序列;

时间复杂度:O(NlgN);

 1 void merge(int arr[], int low, int mid, int high)
 2 {
 3     int *p_tmp_array = NULL, len = 0;
 4     if(NULL == arr)
 5     {
 6         return ;
 7     }
 8     len = high - low + 1;
 9     p_tmp_array = (int*)calloc(1, len * sizeof(int));
10     for(int i = 0; i < len; i++)
11     {
12         p_tmp_array[i] = arr[low + i];
13     }
14 
15     for(int i = low, j = mid + 1, k = 0; k < len; )
16     {
17         if(i > mid )
18         {
19             arr[low + k] = p_tmp_array[j - low];
20             j++;
21             k++;
22         }
23         else if (j > high)
24         {
25             arr[low + k] = p_tmp_array[i - low];
26             i++;
27             k++;
28         }
29         else if(p_tmp_array[i - low] > p_tmp_array[j - low])
30         {
31             arr[low + k] = p_tmp_array[j - low];
32             j++;
33             k++;
34         }
35         else
36         {
37             arr[low + k] = p_tmp_array[i - low];
38             i++;
39             k++;
40         }
41     }
42 
43 }
44 void _msort(int arr[], int low, int high)
45 {
46     int mid = (low+high)/2;
47     if(low >= high)
48     {
49         return ;
50     }
51 
52     _msort(arr, low, mid);
53     _msort(arr, mid+1, high);
54     merge(arr, low, mid, high);
55 }
56 
57 void merge_sort(int arr[], int len)
58 {
59     int mid = 0;
60     if(NULL == arr || len <= 1)
61     {
62         return ;
63     }
64 
65     _msort(arr, 0, len-1);
66 }
View Code

8. 计数排序

  • 找到初始序列中的最大元素max和最小元素min;
  • 分配一个大小为max-min=k的数组,数组的下标表示待排序的值,数组的值表示该下标出现的次数;
  • 遍历初始序列,对数据进行填充,比如a[i]=count,表示元素i出现了count次;
  • 遍历数组,进行反向填充则排序完成;

时间复杂度:O(N+k)

适用情况:k << N,比如对一个公司所有员工的年龄排序;

9. 基数排序

  • 找到初始序列中的最大数,并得到位数d;
  • 从最低位开始对序列进行计数排序;
  • 一直到最高位排好序后,则排序完成;

时间复杂度:O(N×d);

适用情况:电话号码、年月日等;

10. 桶排序

  • 设置桶大小为BucketSize,即每个桶可以放多少个不同的数值;
  • 遍历初始序列,将每个数据放入对应的桶里面,并同时对每个桶排序,比如插入排序;
  • 把所有桶拼接起来就是最终的排序序列,即排序完成;

时间复杂度:???

适用情况:序列基本有序;

转载于:https://www.cnblogs.com/bo1990/p/11379074.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值