考纲

(只考虑内部排序)
1插入排序(直插(稳),希尔)
2交换排序(冒泡(稳),快排)
3选择排序(简选,堆排)
4归并排序(稳)
5基数排序(稳)
6算法笔记

对任意n个关键字排序的比较次数至少为log₂(n!)

1.插入排序

1.1.直接插入排序(稳定)
适合顺序表,也可适用于链表,所以两个都需实现
(用折半查找优化时,只能用顺序表!!!)

1.查找插入位置(外部大循环)//第一个元素总是有序的,从第二个开始比较
2.后移(内部小循环)
void InsertSort(ElemType A[],int n){    //顺序表实现直接插入排序
//1.第一步找插入位置for(int i=2;i<=n;i++){               //从第二个元素比较之前有序的序列,找到if(A[i]<A[i-1]){      //如果if一直不成立,则空循环n趟就完了,若if成立(存在一个数小于其前驱),则进行插入操作A[0]=A[i];         //哨兵暂存“待插入点”for(int j=i-1;A[0]<A[j];--j){   //在待插点之前的有序序列中查找位置A[j+1]=A[j];        //不断后移}A[j+1]=A[0];       //最后的位置为j+1,因为是--j,最后一次循环的时候减了1}// (if)} //(for)
}折半优化查找可减少比较次数!!但不减少移动次数
void InsertSort(ElemType A[],int n){    //顺序表实现直接插入排序
//1.第一步找插入位置for(int i=2;i<=n;i++){               //从第二个元素比较之前有序的序列,找到if(A[i]<A[i-1]){      //如果if一直不成立,则空循环n趟就完了,若if成立(存在一个数小于其前驱),则进行插入操作(这个位置的代码改变,外面的大循环是不变的)1.由顺序查变为折半查,2.边查边后移变为,先查到再统一后移。}// (if)//为啥改进过的直插,还是O(n²)?这里看到两个for循环,外层大循环,套这里的移动小循环。for(j=i-1;j>=high+1;--j){         //找到位置了 就是 low或 high+1;A[j+1]=A[j];                   //统一后移}A[high+1]=A[0];        //或  A[low]=A[0]} //(for)
}具体代码
int low,high,mid;
A[0]=A[i];
low=1;high=i-1;       //折半的范围是 从第一个到第i-1个(有序的序列)while(low<=high){       //这个while+if 是由那个for转化来的,mid=(low+high)/2;if(A[mid]>A[0])high=mid-1;elselow=high+1;
}单链表实现
//需要声明三个指针,p(工作指针,大循环), pre(工作指针,小循环), r(暂存p的后继,防止断链)
void InsertSort(LinkList &L){LNode *p=L->next;LNode *pre,*r=p->next;    //这里的r存p->next,即初始时的第二个元素,p一会就把表搞断,先存着p->next=null;                //为什么p后继赋值null?表示只有一个数据,肯定有序,(所以采用r来暂存p的后继,不然就断了p=r;    //p把表搞断之后,它再从第二个元素开始后移!while(p){          //大循环,p不断后移r=p->next;        //r暂存ppre=L;       //pre小循环,每次都得从头开始比较while(pre->next!=null&&pre->next->data<p->data)       //什么时候退出循环,pre=pre->next;            //1.所有的全比p小,pre后移到的最后,即pre=p,则pre->next空了,退出;//2在前面的有序序列中,找到了比p大的,则不满足第二个条件,退出,此时pre->next值大于p,pre小于p,应插入pre后面p->next=pre->next;       //插入操作  p插在pre后面pre->next=p;p=r;       //r暂存的后继 还给p}
}

1.2.希尔排序(不稳)
又称缩小增量排序
基本思想:先将待排序列分割,把相隔某个“增量”的记录组成一个子表,对各个子表分别用直插,整体有序后,整体再一次直插。
仅适用于顺序表,且不稳定,时间复杂度最坏O(n²),平均为O(n的1.3次方)
希尔排序出算法题的几率微乎其微,基本都是选择题,

void ShellSort(Elemtype A[]){int d,i,j;for(d=n/2;d>=1;d=d/2)                   //初始增量为 n/2for(i=d+1;i>=n;++i){                 //这一层其实是在各个子表来回跳着比的A[0]=A[i];                              for(j=i-d;j>0&&A[0]<a[j];j=j-d){            //就是内部循环,只不过增量不是1(直插), 而是dA[i+d]=A[j];A[j+d]=A[0];}       }
}

2.交换排序

2.1 冒泡排序(稳)
链表也能用

void BubbleSort(ElemType A[],int n){for(int i=0;i<n;i++){flag=false;      //本趟是否发生交换for(int j=n-1;j>i;j--){if(A[j-1]>A[j]){swap(A[j-1],A[j]);flag=true;}  if(flag==false) return; //此趟没发生任何交换,表已经有序}}
}

2.2 快速排序(不稳)
任意枢轴时,须将该值与首元素进行交换,又变为了首元素为枢轴。
时间复杂度为 O(n*递归层数) ------>平均为O(nlog₂n),最坏O(n²)
空间复杂度=O(递归层数)------->平均O(log₂n),最坏为O(n)

每一趟可确定枢轴的位置!

void QuickSort(ElemType int A[],int low;int high){if(low<high){int pivotpos=Partition(A,low,high);  //划分QuickSort(A,low,pivotpos-1);QuickSort(A,pivotpos+1,high);}
}
核心函数:划分
int Partition(ElemType int A[],int low;int high) {  //一趟划分ElemType pivot=A[low];       //把第一个元素设为枢轴,进行划分while(low<high){while(low<high&&A[pivot]>=A[high]) --high;A[low]=A[high];        //比枢轴小的元素移动到左端while(low<high&&A[pivot]<=A[high]) ++low;A[high]=A[low];        //比枢轴大的元素移动到右端}A[low]=pivot;       //枢轴元素存放到最终位置 lowreuturn low;
}

3.选择排序

3.1简单选择排序(不稳)
可以链表
加粗样式用min记录最小的一个
每一趟找到一个最小的值,下趟就可以少遍历一个。
比较次数与初始序列无关,循环必须执行完,不能提前退出

void SelectSort(ElemType A[],int n){for(int i=0;i<n;i++){min=i;               //min 保存最小值的位置(当前最小值设为开始遍历的第一个元素for(int j=i+1;j<n;j++)        //从i后找是否有比A[min]小的if(A[j]<A[min])    min=j;     //循环必须执行完毕,不会提前停止if(min!=i) swap(A[i],A[min]);  //全部遍历完,才能找到最小值。发生交换}
}链表存储
void SelectSort(LinkLIst &L){LNode *h=L;LNode *p,*q,*r,*s; //  p是工作指针,q是其前驱, s是记录最大结点,r是其前驱L=null;while(h!=null){p=s=h;q=r=null;while(p!=null){if(p->data>s->data){s=p;r=q;}        //更大的就替换q=p;p=p->next;                     //没有就后移 }if(s==h) h=h->next;  //最大的还是h没有变化,第一个元素elser-next=s->next;        .//最大的s不是h了,摘下来放到队首s->next=L;L=s;       //无头节点的单链表}
}

3.2堆排序(不稳)
建立大根堆,每次都取堆顶(最大值),则可实现排序。
涉及到三个代码:1.初始建堆 2.调整为大顶堆 3.堆排序
每一趟复杂度是O(树高)->O(logn),最坏为O(n), n趟那就是O(nlogn)
空间复杂度为O(1)

建堆时间 O(n),总比较次数不超过4n

1.建堆
void BuildMaxHeap(ElemType A[].int len){for(int i=len/2;i>0;i--)        //每个非终端结点都调用一次调整堆HeadAdjust(A,i,len);
}2.调整堆
void HeadAdjust(ElemType A[],int k;int len){
//j将k为根的子树进行调整A[0]=A[k];       //A[0]暂存子树的根节点for(i=2*k;i<=len;i=2*i){    //只有非终端结点需要调,一定要从最后一个非终端开始调节if(i<len&&A[i]<A[i+1])   //左右孩子中,较大的是右孩子,则把i=k改为i=k+1i++;if(A[0]>=A[i]) break; //不需要换,根比左右孩子中最大,还要大else{A[k]=A[i]; k=i;           //k不断下坠,直到符合大顶堆,}}
}void HeapSort(ElemType A[],int len){BuildMaxHeap(A,len);       //建堆for(i=len;i>1;i--){         //大循环Swap(A[i];A[1]);       //交换堆顶和最后一个元素,然后可以把当前最后的元素(堆顶)输出后删了HeadAdjust(A,1,i-1);    //重新调整删除后的堆}
}

4.归并排序(稳)

每趟归并时间复杂度O(n),归并趟数(log₂n)向上取整,所以时间复杂度为O(nlog₂n)

空间复杂度 O(n),需要辅助数组n个空间

void MergeSort(int A[],int low,int high){if(low<high){int mid=(low+high)/2;MergeSort(A,low,mid-1);      //左划分       MergeSort(A,mid+1,high);   //右划分,先一路递归到底层,Merge(A,low,mid,high);     //合并         再向上回退合并}
}核心函数 Merge
ElemType *B=(ElemType*)malloc((n+1)*sizeof(ElemType));  //辅助数组B
void Merge(ElemType A[],int low,int mid,int high){int k,i,j;for(k=low;k<=high;k++)B[k]=A[k];            //把A全部赋给Bfor(i=low,j=mid+1,k=i;i<=mid&&j<=high;k++){
//分成了两部分i,j:限定i∈[low,mid],j∈[mid+1,high] ,k是比较次数if(B[i]<=B[j])         //两部分较小的一个加入AA[k]=B[i++];        //然后再自增,进行下一个元素的比较elseA[k]=B[j++];}while(i<=mid) A[k++]=B[i++];  //前半部分没完while(j<=high) A[k++]=B[j++];  //或后半部分没完
}

5.基数排序(稳)

一趟分配需要 O(n),一趟收集需要O®,需要d趟
则时间复杂度为 O(d(n+r))

一趟需要辅助空间为r(r个队列—即r个队头和队尾指针),每一趟都重复利用
空间复杂度为O®

最高位优先法(MSD)
按关键字位权重递减依次逐层划分
先高位,再低位
最低位优先法(LSD)
与之相反

十进制的数 各位都是0~9,所以基数(队列数量) r=10;
个位十位百位,若一个三位数,则需要三趟分配和三趟收集

算法笔记

1.快速排序非递归算法,记忆待排序两个端点,能否用队列实现这个栈
2.双向冒泡排序
3.奇数移动到偶数前面
4.第k小的数
5.荷兰国旗问题,红白蓝排序
6.前m个元素递增有序,后n个元素递增有序,合成一个有序序列
(归并排序或从n+1开始进行n次直插)

1.快速排序非递归算法,记忆待排序两个端点


void QuickSort(int* array, int left, int right)
{stack<int> s;    //初始化一个栈s.push(left);   s.push(right); //存两个端点while (!s.empty()){int right = s.top();      //先取右端点s.pop();int left = s.top();     //再取左端点s.pop();//划分左右部分的边界线int pivot= Partition(array, left, right);if (pivot- 1 > left)            //左半部分,的左右端点{s.push(left);s.push(pivot- 1);}if (pivot+ 1 < right)        //右半部分,的左右端点 {s.push(pivot+ 1);s.push(right);}}}

2.双向冒泡排序

void BubbleSort(ElemType A[],int n){      //正反交替排序int low=0;high=n-1;bool flag=true;while(low<high&&flag){flag=false;     //每一趟开始前都置为flase,发生交换才置为truefor(int i=low;i<high;i++){ //从前往后冒泡if(A[i]>A[i+1]){        //发生逆序,为什么不是A[i-1]>A[i]?,因为low=0啊!而不是1swap(A[i],A[i+1]);flag=true;}}high--; //更新上界,从前往后冒泡结果为:最大的冒到最后,上界有序for(int i=high;i>low;i--){    //从后往前冒泡if(A[i]<A[i-1]){     //发生逆序,为什么不是A[i+1]<A[i]?,因为high=n-1啊!而不是nswap(A[i],A[i-1]);flag=true;}}low++; //更新下界,从前往后冒泡结果为:最小的冒到最前,下界有序}
}

3.奇数移动到偶数前面
基于快排思想:只需遍历一趟,从前往后找到一个偶数,再从后往前找到一个奇数,两者交换,直到low>high.

void move(ElemType A[],int len){int low=0;high=len-1;while(low<high){while(low<high&&A[low}%2==0) low++;  //找到一个是偶数,位置为lowwhile(low<high&&A[high}%2!=0) high--;  //找到一个是奇数,位置为highif(low<high){swap(A[low],A[high]);    //交换两者low++;high--;   //继续比}}
}

4.第k小的数
基于快排思想,选定轴值pivot,划分为两个部分,若轴值左边部分有k-1个元素,则轴值即为第k小的数,否则再向左右两部分去寻找。

void kth_elem(int a[],int low,int high,int k){int pivot=a[low];int low_temp=low;  //由于下面会修改low与high,递归又要用到他们,所以暂存int high_temp=high;while(low<high){while(low<high&&a[high]>=a[pivot])    --high;a[low]=a[high];while(low<high&&a[low]<=a[pivot]) ++low;a[high]=a[low];}a[low]=a[pivot];
//以上全是快排代码
//下面开始联系题目了if(low==k)         //轴值就是k,reutrn a[low];else if(low>k)      //在左边找return kth_elem(a,low_temp,pivot-1,k);elsereturn kth_elem(a,pivot+1,high_temp,k-pivot)   //在右侧找,找第k个??第(k-轴值)个
}

5.荷兰国旗问题,红白蓝排序
思想:将红色交换到最前面,蓝色交换到线性表最后面。
设立三个指针,p,i,k
p为工作指针,表示当前扫描的元素,
i以前的元素全部为红色,
k以后的元素全部为蓝色
初始时 i=0,k=n-1.

void Flag_arrange(color a[],int n){int i=0,p=0,k=n-1;while(p<=k)switch(a[p]){     //判断颜色case RED:Swap(a[i],a[p]);i++;p++;break;   //p不停后移,遇到红色就与前面的交换,case WHITE:p++;break;   //遇到白色啥也不干,p后移case BULE:Swap(a[p],a[k]);k--;  //为什么不p++了??,p不能后移!万一交换过来的也是蓝}
}

考研算法笔记(排序)相关推荐

  1. 算法笔记-排序算法(冒泡 选择 插入)

    首先罗列一下常见的十大排序算法: 一.冒泡排序 1. 定义: 冒泡排序(Bubble Sorting)的基本思想是:通过对待排序序列从前向后(从下标较小的元素开始),依次比较相邻元素的值,若发现逆序则 ...

  2. 算法笔记 排序 EXCEL排序

    题目描述: Excel可以对一组纪录按任意指定列排序.现请你编写程序实现类似功能. 对每个测试用例,首先输出1行"Case i:",其中 i 是测试用例的编号(从1开始).随后在 ...

  3. 二、考研数据结构笔记——绪论(理解数据结构,算法,时间复杂度计算做题技巧)

    一.数据结构基本概念 1.数据:数据是信息的载体.客观事物的一种表现形式.万事万物都能用数据表示出来. 2.数据元素:数据元素是数据的基本单位,一个数据元素有若干个数据项组成 3.数据项:构成数据元素 ...

  4. 算法笔记(JavaScript版)——排序

    算法笔记(JavaScript版)--排序 本文内容根据Rebert Sedgewick和Kevin Wayne的<算法(第四版)>整理,原代码为java语言,自己修改为JavaScrip ...

  5. 大话数据结构读书笔记艾提拉总结 查找算法 和排序算法比较好 第1章数据结构绪论 1 第2章算法 17 第3章线性表 41 第4章栈与队列 87 第5章串 123 第6章树 149 第7章图 21

    大话数据结构读书笔记艾提拉总结 查找算法 和排序算法比较好 第1章数据结构绪论 1 第2章算法 17 第3章线性表 41 第4章栈与队列 87 第5章串 123 第6章树 149 第7章图 211 第 ...

  6. 考研数据结构笔记--数据结构和算法的基本概念

    考研数据结构笔记--数据结构和算法的基本概念 数据结构的基本概念 算法的基本概念 数据结构的基本概念 数据 数据是对客观事物的符合表示,在计算机科学中是指所有能输入到计算机中并且被计算机程序处理的符合 ...

  7. 漫画算法笔记 桶排序

    漫画算法笔记 桶排序 #include <iostream> #include <stdlib.h> #include <algorithm> #include & ...

  8. 算法入门之排序(《算法笔记》)

    <算法笔记>的笔记嘻嘻 冒泡排序 选择排序 插入排序 使用sort函数排序

  9. Contest100000581 - 《算法笔记》4.1小节——算法初步-排序

    文章目录 Contest100000581 - <算法笔记>4.1小节--算法初步->排序 1.讲解 4.1 .1 选择排序 4.1.2 插入排序 4.1.3 排序题与sort()函 ...

最新文章

  1. OSChina 周六乱弹 —— 就少个接吻的女友了
  2. 内链优化对于网站有哪些作用?
  3. 【数据科学】鱼水说竞赛:如何做好「特征工程」?
  4. MongoDB中如何优雅地删除大量数据
  5. Spring-JdbcTemplate基本使用
  6. 使用 Moq 测试.NET Core 应用 -- Mock 方法
  7. 扩散方程——热传导问题(能量定律+傅里叶热传导定律)+ 拉普拉斯方程 | 偏微分方程(三)
  8. ESP8266-Arduino网络编程实例-HightCharts实时图表显示BME280数据
  9. c#中调用window的 wmi服务获取本机usb信息
  10. WordPress一款简约轻快且强大的MDx主题
  11. MATALB APP DESIGNER 回调函数创建及StartupFcn函数
  12. html界面——button设置样式
  13. 为什么要学习Linux及其学习路线
  14. 哀悼日网页彩色变黑白方法-css样式修改
  15. 金融工程---引论以及参考书目
  16. CCF CSP 压缩编码
  17. There is no getter for property named ‘user’ in ‘class’问题
  18. 7-2 打印学生选课清单 (25分)(c++)
  19. 2022年山东省职业院校技能大赛高职组 “软件测试”赛项竞赛任务书
  20. 分享一些百度收录又快又好的平台,用好它们做推广有奇效!

热门文章

  1. 长城汽车室外AGV无线应用方案
  2. sscom 中文显示 乱码_SSM框架:解决后台传数据到前台中文乱码问题,使用@ResponseBody返回json 中文乱码 Web程序 - 贪吃蛇学院-专业IT技术平台...
  3. java 后端开发技能_Java 后端开发,应该重点学习哪些知识/技能?
  4. 中国焦炭行业发展现状及趋势分析,提高市场集中度「图」
  5. 安装ACR122U后Proxmark3无法使用
  6. 分享功能(分享到新浪微博、腾讯微博、人人网、QQ空间。。。)
  7. Motrix for Mac(全能高速下载工具)
  8. 这里有一份最新的课程分享清单,收集好久了,请查收
  9. 一条sql是如何执行的
  10. 谜题21:我的类是什么?