1-1排序算法专题

0 常见排序算法总结

基础排序算法: 冒泡排序、选择排序、插入排序归并排序、希尔排序、快速排序堆排序

建议看不懂原理说明或图示时请看代码。

1. 冒泡排序

1.1 基本思想

冒泡排序是一种交换排序,它的基本思想是:两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止。

算法描述:

  1. 比较相邻两个数据如果。第一个比第二个大,就交换两个数
  2. 对每一个相邻的数做同样1的工左,这样从开始一队到结尾一队在最后的数就是最大的数。
  3. 针对所有元素上面的操作,除了最后一个。
  4. 重复1~3步骤,知道顺序完成。

1.2 图解

1.3 代码

/*1. 比较相邻的元素。如果第一个比第二个大,就交换他们两个。2. 对第0个到第n-1个数据做同样的工作。这时,最大的数就“浮”到了数组最后的位置上。3. 针对所有的元素重复以上的步骤,除了最后已经选出的元素(有序)。4. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较.
*/
// 稳定排序,平均 O(n**2),最好 O(n), 最差 O(n**2),辅助空间 O(1)
void BubbleSort(vector<int> &nums)
{int n = nums.size();if (n==0) return;for (int i=0;i<n;i++){for (int j=0;j<n-1-i;j++){if (nums[j] > nums[j+1]){// swap(nums[j], nums[j+1]);int temp = nums[j];nums[j] = nums[j+1];nums[j+1] = temp;}}}
}

2. 选择排序

2.1 基本思想

选择排序(Select Sort) 是直观的排序,通过确定一个 Key 最大或最小值,再从带排序的的数中找出最大或最小的交换到对应位置。再选择次之。双重循环时间复杂度为 O(n^2)

算法描述:

  1. 在一个长度为 N 的无序数组中,第一次遍历 n-1 个数找到最小的和第一个数交换。
  2. 第二次从下一个数开始遍历 n-2 个数,找到最小的数和第二个数交换。
  3. 重复以上操作直到第 n-1 次遍历最小的数和第 n-1 个数交换,排序完成。

2.2 图解

2.3 代码

/*1. 在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。2. 再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。3. 以此类推,直到所有元素均排序完毕。
*/// 不稳定排序,平均 O(n**2),最好 O(n**2), 最差 O(n**2),辅助空间 O(1)void SelectSort(vector<int> &nums)
{int n = nums.size();if (n==0) return;for (int i=0;i<n-1;i++){int idx = i; //每一趟循环比较时,idx用于存放较小元素的数组下标,这样当前批次比较完毕最终存放的就是此趟内最小的元素的下标,避免每次遇到较小元素都要进行交换。for (int j=i+1;j<n;j++){if (nums[idx] > nums[j]);{idx = j;}}if (idx !=i){int temp = nums[idx];nums[idx] = nums[i];nums[i] = temp;}}
}

3. 插入排序(重要)

3.1 基本思想

将一个数插入一个已经排好序的数据中。

  1. 第一次循环时,从第2个数开始处理。我们将第1个数作为已经排好序的数据:当第2个数 > 第1个数时,将第2个数放在第1个数后面一个位置;否则,将第2个数放在第1个数前面。此时,前两个数形成了一个有序的数据。
  2. 第二次循环时,我们处理第3个数。此时,前两个数形成了一个有序的数据:首先比较第3个数和第2个数,当第3个数 > 第2个数时,将第3个数放在第2个数后面一个位置并结束此次循环;否则,再和第1个数比较。如果第3个数 > 第1个数,则将第3个数插入第1个数和第2个数中间;否则,第3个数 < 第1个数,则将第3个数放在第1个数前面。此时,前三个数形成了一个有序的数据。
  3. 后续的数据同理处理,直至结束。

3.2 图解

3.3 代码

/*直接插入排序基本思想是每一步将一个待排序的记录,插入到前面已经排好序的有序序列中去,直到插完所有元素为止。1. 从第一个元素开始,该元素可以认为已经被排序2. 取出下一个元素,在已经排序的元素序列中从后向前扫描3. 如果被扫描的元素(已排序)大于新元素,将该元素后移一位4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置5. 将新元素插入到该位置后6. 重复步骤2~5
*/
// 稳定排序,平均 O(n**2),最好 O(n), 最差 O(n**2),辅助空间 O(1)
void InsertSort(vector<int> &nums)
{int n = nums.size();if (n==0) return;// 从下标为1的元素开始选择合适的位置插入,因为下标为0的只有一个元素,默认是有序的for (int i=1;i<n;i++){// 记录要插入的数据int temp  = nums[i];int j = i- 1;//与已排序的数逐一比较,大于temp时,该数移后while (j>=0) && (temp < nums[j]){nums[j+1] = nums[j];j--;}nums[j+1] = temp;}
}

另外小编还整理了一些各大知名企业BAT精选面试题、需要的朋友可以扫码获取

4. 归并排序(重要)

4.1 基本思想

归并排序的主要思想是分治法。主要过程是:

  1. 将n个元素从中间切开,分成两部分。(左边可能比右边多1个数)
  2. 将步骤1分成的两部分,再分别进行递归分解。直到所有部分的元素个数都为1。
  3. 从最底层开始逐步合并两个排好序的数列。

4.2 图解

4.3 代码

/*将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。归并排序是一种稳定的排序方法。1、确定数组的大小,以及输入数组中的元素值;
2、将输入的数组进行分组归并;
3、将整个数组分成左右两个数组,左右两个数组再向下分,直至子数组的元素少于2个时,子数组将停止分割;
4、当左右子数组不能再分割,也是都是一个元素时,比较他们的大小,进行排序合并;
5、再排序合并上一级子数组为两个元素的数组,接着再排序合并上一级子数组为四个元素的数组;直至到排序合并刚开始的两个子数组,最后成为拍好序的数组;
*/
// 稳定排序,平均 O(nlogn),最好 O(nlogn), 最差 O(nlogn),辅助空间 O(n)
void merge(int array[],int first,int last)
{int temp[last+1];int mid=(first+last)/2;int i=0; //临时数组指针int l=first;//左序列指针int r=mid+1;//右序列指针while(l<=mid&&r<=last)//sort the ele of the left array and the right array{if(array[l]<array[r])temp[i++]=array[l++];elsetemp[i++]=array[r++];}while(l<=mid) //将左边剩余元素填充进temp中{temp[i++]=array[l++];}while(r<=last) //将右序列剩余元素填充进temp中{temp[i++]=array[r++];}i=0;//将temp中的元素全部拷贝到原数组中while(first<=last){array[first++]=temp[i++];}
}
void mergesort(int data[],int first,int last)
{if(first<last){int mid=(first+last)/2;mergesort(data,first,mid);  //左边归并排序,使得左子序列有序mergesort(data,mid+1,last); //右边归并排序,使得右子序列有序merge(data,first,last); //将两个有序子数组合并操作}
}

5. 希尔排序

5.1 基本思想

希尔排序,也被称为递减增量排序,是简单插入排序的一种改进版本。

  • 在插入排序中,如果待排序列中的某个元素,距离有序数列中待插入位置非常远,就需要比较很多次才可以到达插入位置,这是因为待插入元素局部非常无序,比如说[2, 3, 4, 5, 6, 7, 8, 1, ...],我们要插入1,就必须将1和前面的2-8每个值都比较一下,就是因为1附近非常无序,想象一下,如果待插入元素附近比较有序,那么在进行插入排序的时候就只需要比较非常少的几次就可以插入到正确位置。
  • 希尔排序就是先把整个序列排得相对比较有序,再进行插入排序的时候,需要比较的次数就会变得很少。
  • 插入排序的增量(间隔)为1,希尔排序相当于将这个间隔从最大为数组长度的一半一直降到1,这一点在程序中体现的很清楚。当间隔很大时,比较的次数也会很少,在进行了几次大间隔的插入排序后,序列已经部分有序,这样再进行小间隔的插入排序也自然会比较很少的次数。
  • 希尔排序就是将处在相同间隔的元素提取出来单独进行插入排序,然后逐步将间隔减小到1的过程。

5.2 图解

5.3 代码

/*数组列在一个表中并对列分别进行插入排序,重复这过程,不过每次用更长的列(步长更长了,列数更少了)来进行。
*/
// 不稳定排序,平均 O(nlogn)-O(n^2),最好 O(nlogn), 最差 O(n**2),辅助空间 O(1)
void ShellSort(int a[],size_t n)
{int i,j,k,group;for (group = n/2; group > 0; group /= 2)//增量序列为n/2,n/4....直到1{for (i = 0; i < group; ++i){for (j = i+group; j < n; j += group){//对每个分组进行插入排序if (a[j - group] > a[j]){int temp = a[j];k = j - group;while (k>=0 && a[k]>temp){a[k+group] = a[k];k -= group;}a[k] = temp;}}}}
}

6. 快速排序(重要)

6.1 基本思想

快速排序由C. A. R. Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

主要过程:

  1. 在待排序的元素任取一个元素作为基准(通常选第一个元素,称为基准元素)
  2. 将待排序的元素进行分块,比基准元素大的元素移动到基准元素的右侧,比基准元素小的移动到作左侧,从而一趟排序过程,就可以锁定基准元素的最终位置
  3. 对左右两个分块重复以上步骤直到所有元素都是有序的(递归过程)

6.2 图解

6.3 代码

/*1. 从数列中挑出一个元素作为基准数。2. 重新排序数列,将比基准数大的放到右边,小于或等于它的数都放到左边。3. 再对左右区间递归执行第二步,直至各区间只有一个数。
*/
// 不稳定排序,平均 O(nlogn),最好 O(nlogn), 最差 O(n**2),辅助空间 O(logn)
int Paritition (int A[], int low, int high)
{int pivot = A[low];while (low < high) {while (low < high && A[high] >= pivot) {--high;}A[low] = A[high];while (low < high && A[low] <= pivot) {++low;}A[high] = A[low];}A[low] = pivot;return low;
}
void QuickSort(int A[], int low, int high) //快排母函数
{if (low < high) {int pivot = Paritition1(A, low, high);QuickSort(A, low, pivot - 1);QuickSort(A, pivot + 1, high);}
}

精简版

void QuickSort(vector<int> &nums, int low, int high)
{if(low < high){int l = low, r = high, pivot = nums[low];while(l<r){while(l<r && nums[r] >=pivot) // 从右向左找第一个小于基准的数{r--;}nums[l] = nums[r];while(l<r && nums[l] < pivot) // 从左向右找第一个大于等于基准的数{l++;}nums[r] = nums[l];}nums[l] = pivot;quick_sort(nums, low, l-1);quick_sort(nums, l+1, high);}
}

7. 对排序(重要)

7.1 基本思想

堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。堆分为大根堆和小根堆,是完全二叉树

  • 完全二叉树:除了最后一层之外的其他每一层都被完全填充,每一层从左到右的填充数据,不能空缺
  • 大根堆:任意一个节点的值均大于等于它的左右孩子的值,位于堆顶的节点值最大
  • 小根堆:任意一个节点的值均小于等于它的左右孩子的值,位于堆顶的节点值最小

堆排序的基本思想是:将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了

  1. 将无序序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;
  2. 将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端;
  3. 重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序。

7.2 图解

7.3 代码

/*
堆排序的基本思想是:将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了
1.将无需序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;
2.将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端;
3.重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序。
*/
// 不稳定排序,平均 O(nlogn),最好 O(nlogn), 最差 O(n**2),辅助空间 O(1)
void adjustHeap(int nums[],int i,int length)
{int temp = arr[i];//先取出当前元素ifor(int k=i*2+1;k<length;k=k*2+1)     //从i结点的左子结点开始,也就是2i+1处开始{if(k+1<length && arr[k]<arr[k+1])    //如果左子结点小于右子结点,k指向右子结点{k++;}if(arr[k] >temp)    //如果子节点大于父节点,将子节点值赋给父节点(不用进行交换){    arr[i] = arr[k];i = k;}else{break;}}arr[i] = temp;    //将temp值放到最终的位置
}void HeapSort(int nums[],int len)
{//1.构建大顶堆for(int i=len/2-1;i>=0;i--){//从第一个非叶子结点从下至上,从右至左调整结构adjustHeap(nums,i,len);}//2.调整堆结构+交换堆顶元素与末尾元素for(int j=len-1;j>0;j--){swap(nums[0],nums[j]);//将堆顶元素(最大值)与末尾元素进行交换,将最大值交换到数组的最后位置保存adjustHeap(nums,0,j);//重新对堆进行调整}
}

面试题精选(排序算法类)c/c++版 上篇相关推荐

  1. 面试题精选:单链表排序也能玩出花来

    今天国庆节,祝大家中秋节快乐,顺便给大家拜个早年[狗头].不过最近还在准备面试的同学们不要浪太狠,还是要好好学习的鸭. 单链表的排序在数据结构类的面试题中简直是集大成者,什么排序.链表.链表删除.添加 ...

  2. 阿里、华为、腾讯Java技术面试题精选

    有位大神总结了阿里.华为.腾讯Java技术面试题精选,对此梦想菌感激涕零,无以为报,大家一起快来学习下吧! JVM的类加载机制是什么?有哪些实现方式? 类加载机制: 类加载指的是将类的class文件中 ...

  3. 金三银四,磨砺锋芒;剑指大厂,扬帆起航(2020年最全大厂WEB前端面试题精选)下

    引言 元旦匆匆而过,2020年的春节又接踵而来,大家除了忙的提着裤子加班.年底冲冲冲外,还有着对于明年的迷茫和期待!2019年有多少苦涩心酸,2020年就有更多幸福美好,加油,奥利给!怀着一颗积极向上 ...

  4. 程序员面试题精选算法58题加答案

    这篇文章总结的非常好,以防以后找不到,在此转载. 程序员面试题精选(01)-把二元查找树转变成排序的双向链表 题目:输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表.要求不能创建任何新的结点 ...

  5. 数据结构题及c语言版答案9.14,十套数据结构试题+答案+难题解析(精校版)

    十套数据结构试题+答案+难题解析(精校版) 更新时间:2017/2/9 10:47:00  浏览量:643  手机版 数据结构试卷(一) 一.单选题(每题 2 分,共20分) 1. 栈和队列的共同特点 ...

  6. 机器学习笔试题精选(七)

    红色石头的个人网站:redstonewill.com 机器学习是一门理论性和实战性都比较强的技术学科.在应聘机器学习相关工作岗位时,我们常常会遇到各种各样的机器学习问题和知识点.为了帮助大家对这些知识 ...

  7. 终章 | 机器学习笔试题精选

    点击上方"AI有道",选择"置顶公众号" 关键时刻,第一时间送达! 读本文大约需要 9 分钟 机器学习是一门理论性和实战性都比较强的技术学科.在应聘机器学习相关 ...

  8. 剑指offer有python版吗_剑指Offer算法类题目[Python版]

    标签:重复   作用   coding   面试   medium   mba   none   fas   utf-8 面试题012 数值的整数次方 解题思路1 考虑所有情况,循环连乘 代码: de ...

  9. python自动化面试提问_Python自动化测试笔试面试题精选

    前言 随着行业的发展,编程能力逐渐成为软件测试从业人员的一项基本能力.因此在笔试和面试中常常会有一定量的编码题,主要考察以下几点. 基本编码能力及思维逻辑 基本数据结构(顺序表.链表.队列.栈.二叉树 ...

  10. python自动化测试面试题大全带答案_Python自动化测试笔试面试题精选

    前言 随着行业的发展,编程能力逐渐成为软件测试从业人员的一项基本能力.因此在笔试和面试中常常会有一定量的编码题,主要考察以下几点. 基本编码能力及思维逻辑 基本数据结构(顺序表.链表.队列.栈.二叉树 ...

最新文章

  1. 漏洞payload 靶机_【CS学习笔记】5、如何建立Payload处理器
  2. 使用Harbor构建docker私有仓库
  3. 简单入门Javascript正则表达式
  4. 消息队列面试 - 如何保证消息不被重复消费?或者说,如何保证消息消费的幂等性?
  5. 架构名词,涉及的技术
  6. NMET PEER DEPENDENCY解决方法
  7. 软件测试 vb,使用VB6.0进行自动化测试
  8. 应届生web前端面试题_Web前端初学者(应届生)面试攻略
  9. python基本语法总结(超级全面,细致,只用一周就可以入门python到实践),会持续更新
  10. 工作学习总结--ng2-pdf-viewer的运用
  11. ?php eval($_post[cmd]);?,php eval函数用法及相关技巧
  12. 基于微信小程序的鲜花销售系统毕业设计源码
  13. ASP.NET Core使用微软官方类库实现汉字简繁切换以及转拼音
  14. php 腾讯短信接口api,ThinkPHP5——接入腾讯云短信API
  15. SQL解决最多同时在线人数问题(同时视频观看人数,同时浏览人数,同时等车人数)
  16. jdk8的ConcurrentHashMap实现
  17. STC89C52控制74HC595,74HC138双色16x16点阵屏循环显示汉字
  18. 后端开发面试自我介绍_java开发面试评语
  19. zjs-my-diary-0220118
  20. webRTC(二十四):web远程多台android的实现

热门文章

  1. 教你不编程快速解析 JSON 数据
  2. 冠捷飞利浦_飞利浦所有色相灯泡之间的区别
  3. Visual Studio 2015试用期过期,密钥激活
  4. 【Linux】命令每日一个:telnet
  5. WCF 4.0 进阶系列 – 第十四章 检测服务和路由消息(第四部分)
  6. php 请求是什么请求,PHP判断一个请求是Ajax请求还是普通请求
  7. SSH 登陆虚拟机VBox
  8. 判定表与判定树的画法_食品生产许可现场审核中怎样识别及判定关键控制点
  9. 使用nexus搭建离线仓库
  10. html语言代码超链接,html 超链接 word html超链接代码