经典排序算法设计与分析(插入排序、冒泡排序、选择排序、shell排序、快速排序(1)

img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

  1. srand(time(NULL));//生成随机数种子
  2. for (i=0;i<SIZE;i++)
  3. {
  4. buff[i] = rand()/SIZE;//随机生成元素
  5. }
  6. t1=(double)clock()/CLK_TCK;
  7. mySort(buff);//调用排序算法
  8. t2=(double)clock()/CLK_TCK;
  9. printf(“Total time used:%f second\n”,t2-t1);//计算排序所用的事件
  10. printAll(buff,20);//打印前面的元素,用于验证
  11. return 0;
  12. }

1.插入排序(Insert Sort)

用算法导论中的一个例子来形容,插入排序就好像你打扑克摸牌。第一次摸一张10(不用排序);第二次摸一张5,你就需要把5插入到10后面;第三次摸了一张7,你就需要将7插到5的后面、10的前面,以此类推。插入排序的时间复杂度n2。

[cpp]
view plain
copy
print
?

  1. void mySort(int buff[],int len = SIZE)
  2. {
  3. int i,j,key;
  4. for (i = 1;i < len;i++)//i表示你摸了的第i张牌,第一张牌不用排序,可以跳过
  5. {
  6. key = buff[i];//先记住这张牌的值
  7. for (j = i;j > 0 && buff[j-1] > key;j–)//将这张牌依次与它之前的每张牌进行比较,直到找到比它小的牌为止
  8. {
  9. buff[j] = buff[j-1];//在查找的过程中,将对比过的牌向后移。
  10. }
  11. buff[j] = key;//将牌插入到指定位置
  12. }
  13. }

运行结果:

2.冒泡排序(Bubble Sort)

假设有10个数,先比较第10和第9个数,将较小的数存到9的位置;然后比较第9和8个数,此时得到的较小的数也就是第8,9,10中的最小的数。依次类推,当比较完第1和2个数之后,第一个位置存放的数就是所有元素中最小的数。在从第10个开始比较,最终将第2小的数放到第二个位置。依次执行就可以完成排序了。冒泡排序的时间复杂度n2。

[cpp]
view plain
copy
print
?

  1. void mySort(int buff[],int len = SIZE)
  2. {
  3. int i,j,t;
  4. for(i = 0;i < len-1;i++)//最后只剩下一个元素时不需要比较
  5. {
  6. for (j = len-1;j > i;j–)从最后一个元素开始冒泡,只需要比较到i就可以了(因为i之前的元素都已经排好序了)
  7. {
  8. if (buff[j] < buff[j-1])//依次比较相邻的两个元素
  9. {
  10. t = buff[j];
  11. buff[j] = buff[j-1];
  12. buff[j-1] =t;
  13. }
  14. }
  15. }
  16. }

运行结果:

3.选择排序

选择排序和冒泡排序的方法基本类似,只不过它减少了交换了次数。每次比较时都只记录下最小值得下标,不进行时间的交换,直到最后才将得到的下标和第一个元素进行唯一的依次交换。选择排序的时间复杂度n2。

[cpp]
view plain
copy
print
?

  1. void mySort(int buff[],int len = SIZE)
  2. {
  3. int i,j,t;
  4. for(i = 0;i < len-1;i++)//最后只剩下一个元素时不需要比较
  5. {
  6. int index = i;//记录最小值的下标
  7. for (j = len-1;j > i;j–)//从最后一个元素开始冒泡,只需要比较到i就可以了(因为i之前的元素都已经排好序了)
  8. {
  9. if (buff[j] < buff[index])//比较当前元素和当前的最小值
  10. {
  11. index = j;
  12. }
  13. }
  14. //将最小值放到最前面的位置
  15. t = buff[index];
  16. buff[index] = buff[i];
  17. buff[i] = t;
  18. }
  19. }

运行结果:

4.shell排序

希尔排序也称为缩小增量排序(diminishing increment sort),它利用了插入排序最佳时间代价特性(即元素的初始排列就接近于有序,那么插入排序比较的次数最少,循环时间最短)。通过逐渐缩小增量,来将数组尽量的变得有序,再使用插入排序,这样效率更高。选择适量的增量可以提高shell排序的效率。sell排序的时间复杂度n1.5(增量每次除以3)。

[cpp]
view plain
copy
print
?

  1. void insertSort(int buff[],int len = SIZE,int increase = 1)
  2. {
  3. int i,j,key;
  4. for (i = increase;i < len;i+=increase)//以increase为标准取元素
  5. {
  6. key = buff[i];
  7. for (j = i;j >= increase && buff[j-increase] > key;j -= increase)//以increase为元素之间的间隔距离
  8. {
  9. buff[j] = buff[j-increase];
  10. }
  11. buff[j] = key;
  12. }
  13. }
  14. //排序算法
  15. void mySort(int buff[],int len = SIZE)
  16. {
  17. int setp = 2;//每次缩小的倍数,不能为1,为1表示不缩小
  18. int i,j;
  19. for(i = len/setp;i >= 1;i /= setp)
  20. {
  21. for (j=0;j<i;j++)
  22. {
  23. insertSort(buff,len-j,i);
  24. }
  25. }
  26. }

运行结果:

这是shell排序以2为增量的示例图:

5.快速排序

考虑一个BST(二叉搜索树)通过中序遍历得到的有序数组,我们可以知道BST的根节点将树分为两个部分。左子树的所有记录都比根节点要小,右子树的所有记录都比根节点要大。这里就是一种“分治”的思想。同理,将数组根据key来分为两部分,一部分比key要小,一部分比key要大。对每一部分继续划分,直到每个子部分都只包含一个元素,不就是得到了类似BST的数组了吗。快速排序的时间复杂度n*lgn。

[cpp]
view plain
copy
print
?

  1. //交换数组中地址为index1,index2两元素的值
  2. void swap(int buff[],int index1,int index2)
  3. {
  4. int t = buff[index1];
  5. buff[index1] = buff[index2];
  6. buff[index2] = t;
  7. }
  8. //将大数组划分为小数组,使得l左边都是小于keyValue的值,r右边都是大于keyValue的值
  9. int partition(int buff[],int l,int r,int keyValue)
  10. {
  11. do
  12. {
  13. while (buff[++l] < keyValue);//找到从左起,第一个大于keyValue的数,用于交换
  14. while ( r!=0 && buff[–r] > keyValue);//找到从右起,第一个小于keyValue的数,用于交换
  15. /*
  16. 注意之所以要考虑r!=0,是为了应对特殊情况,即所有元素都大于keyValue(即数组本来就有序),
  17. 此时l位于到数组最左边,r一直移动,知道数组的最左边仍然满足buff[–r]>keyValue,继续运动就会越界,所以需要r!=0
  18. */
  19. swap(buff,l,r);//将一个大值和一个小值交换
  20. } while (l<r);
  21. swap(buff,l,r);//由于使用的是do,while,所以在判断l<r之前进行过依次交换,但这次交换是多余的,需要再换回来
  22. return l;//返回分割后右边部分的头位置
  23. }
  24. //排序算法,第一次调用使用mySort(buff,0,SIZE-1)
  25. void mySort(int buff[],int begin,int end)
  26. {
  27. if (end <= begin)//0个或1个元素,此时排序已经完成,不在进行
  28. {
  29. return;
  30. }
  31. int keyIndex = (begin+end)/2;//使用中间值作为比较用的key
  32. swap(buff,keyIndex,end);//将key放到最右边,便于partition中使用
  33. int k = partition(buff,begin-1,end,buff[end]);
  34. swap(buff,k,end);//总是将key放到两个部分的中间
  35. mySort(buff,begin,k-1);
  36. mySort(buff,k+1,end);
  37. }

运行结果:

这里还有另一个版本的快速排序,只不过是以每个部分数组的第一个元素为轴值。

[cpp]
view plain
copy
print
?

  1. int partition(int list[],int low,int high)
  2. {
  3. int tmp = list[low];
  4. while (low < high) {
  5. while (low < high && list[high] >= tmp) {
  6. high–;
  7. }
  8. list[low] = list[high];   //比中轴小的记录移到低端
  9. while (low < high && list[low] <= tmp) {
  10. low++;
  11. }
  12. list[high] = list[low];   //比中轴大的记录移到高端
  13. }
  14. list[low] = tmp;              //中轴记录到尾
  15. return low;
  16. }
  17. //排序算法,第一次调用使用mySort(buff,0,SIZE-1)
  18. void mySort(int list[],int low,int high)
  19. {
  20. if (low < high) {
  21. int middle = partition(list, low, high);  //将list数组进行一分为二
  22. mySort(list, low, middle - 1);        //对低字表进行递归排序
  23. mySort(list, middle + 1, high);       //对高字表进行递归排序
  24. }
  25. }

6.堆排序

堆是一种树形结构,最大堆中所有父节点的值都大于其子节点,最小堆相反。堆排序实质就是不断从最小堆中取出根节点,然后重新调整堆的结构,使它满足堆的性质。堆排序的时间复杂度n*lgn。

[cpp]
view plain
copy
print
?

  1. void swap(int *a,int *b)
  2. {
  3. int t = *a;
  4. *a = *b;
  5. *b = t;
  6. }
  7. /***
  8. * a            待排数组
  9. * rootIndex    本次堆化的根
  10. * maxHeapIndex 本次堆化所达到的堆数组最大索引
  11. */
  12. void maxHeapify2(int a[], int rootIndex,int maxHeapIndex)
  13. {
  14. int lChild = rootIndex*2+1; //左儿子节点
  15. int rChild = rootIndex*2+2;  //右儿子节点
  16. //得到父节点,左右儿子节点中最大的节点,并与父节点交换
  17. int largest = rootIndex;
  18. if(lChild <= maxHeapIndex && a[lChild] > a[rootIndex])
  19. largest = lChild;
  20. if(rChild <= maxHeapIndex && a[rChild] > a[largest])
  21. largest = rChild;
  22. if(largest != rootIndex)
  23. {
  24. swap(&a[largest],&a[rootIndex]);
  25. maxHeapify2(a,largest,maxHeapIndex);
  26. }
  27. }
  28. void heapSort2(int a[],int len)
  29. {
  30. int i=0;
  31. int maxHeapIndex = len-1;
  32. //首先建堆
  33. for(i = (maxHeapIndex-1)/2; i >= 0;i–)
  34. {
  35. maxHeapify2(a,i,maxHeapIndex);
  36. }
  37. //最大的值放到数组末尾,然后对剩下的数组部分进行堆排序
  38. for(i = maxHeapIndex;i >= 1;i–)
  39. {
  40. swap(&a[0],&a[i]);
  41. // 交换之后,继续堆化时,堆数组最大索引要减1
  42. maxHeapify2(a,0,i-1);
  43. }
  44. }
  45. //排序算法
  46. void mySort(int buff[],int len = SIZE)
  47. {
  48. heapSort2(buff,len);
  49. }

运行结果:可以看出堆排序对大数组速度很快的

7.分配排序

示例代码:

[cpp]
view plain

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

7.分配排序

示例代码:

[cpp]
view plain

[外链图片转存中…(img-AvUQVIz2-1715886479263)]
[外链图片转存中…(img-lQJkyjT4-1715886479264)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值