快速排序

  1. 确定分界点:在数组中选一个元素的值 x x x 作为分界,(某人说)可任取
  2. 重点)调整区间:以 x x x 为准,将数组分为左右两段,通过换位保证左边都≤x,右边都≥x,即可
  3. 递归分别处理左右两部分,直到排完

暴力做法:分拣到两个新数组中,再合起来。 硬开数组,空间复杂度过于友好了(笑)

文明做法:设计一个函数,传入待排序数列的两端序号和数组首地址。(若全局数组则不需要地址)

void quick_sort(int q[], int l, int r)

设计函数是方便递归。由于数列结构简单,指针直接用数组下标实现,可专注于数据本身

**双指针算法:**指针 i , j i,j i,j先后从两边出发,直到各发现应属于另一方的数(即第一个不小于/不大于 x x x 的数,等于无需单独处理),接着将两个数对调。一次可处理两个数,之后 i , j i,j i,j继续走自己的路,直到都停下时已相遇或擦肩而过,函数主体结束

因此可保证 i i i 左边是小于等于, j j j 右边是大于等于(等于可随意)。

于是基本结构是循环嵌套,再整体递归

while(i < j)  //在这之前,判断若i >= j,直接跳出函数
{do {i++;} while(q[i] < x);    //小讲究,do while比while更接近汇编逻辑,或许更快do {j--;} while(q[j] > x); //这里规定等于的时候也停(防止x是极值时,停不下来if(i < j) swap(q[i], q[j]);  //如果已经相遇过,说明所有数都扫描完毕,无需交换了
}
quick_sort(q, l, i - 1);    //换成j和j+1也行,因为i j最后都停在了另一侧,所以递归时属于另一侧
quick_sort(q, i, r);

注意:采用 do while 循环使得代码精简,起步前先将 i i i, j j j下标外移一格,每次先移动再判定。

一般从数组中取基准 x x x ,示例取了左边界q[l]

但取边界 x x x 可能有如下问题:

因为规定等于也停,所以第一轮必有一边停在起点。

如果脸不好,对面直接贴脸了,循环结束。于是两个递归中,一个边界错位直接退回,另一个边界不变,无限循环。

这样就充分解释了为何递归时传 i i i 的话 x x x 不能取 q[l],传 j j j 的话 x x x 不能取 q[r]。

因此干脆取中间值就行了。

int x = q[l + r + 1>> 1];    //+-优先级大于>>,后者比 /2 快几十倍
//为防止数组只有2个,递归取i要+1         取j不+1

补充

  1. scanf读入一般比cin更快

补充: c++中为了保证与c的兼容,将输入输出与c的方式绑定,导致 cin 效率降低。

  1. ios::sync_with_stdio(false); ——关闭 cinstdio 的兼容,提高 cin 效率
    但使用之后要注意,不能将 cin coutscanf printf 混用

  2. cin.tie() ——可人为设置输入输出流的绑定
    其中无参数时 cin 只绑定 cout ,也可以加速输入

  3. 对于简单数据可以一律用 scanf

  1. 用异或运算交换两个数(联想基因传递和表达x
a ^= b;
//用异或标记a和b二进制中不同的位。结果保存给a
b ^= a;
//照着a的密码,1对应位取反,0对应位不变。翻译成了原先的a
a ^= b;
//以自己为密码,由现在的b翻译出原先的b

特点是快!而且省空间!能用的场合可以无脑。

但要避免指针导致的自交换,会清零数据。必要时还是用第三者赋值法,保险


归并排序

快速排序:先粗排,再递归细化

归并排序:先递归二分,再边排序边合并(归并)

  1. 分界点:mid = (l + r) / 2

  2. 二分

**重点:**快排在于分的时候完成排序,而归并在于合的时候完成排序(合并数组或链表)

双指针算法:(递归结束后)定义两个指针分别指向两个数组片段左端

每次选较小数填入新数组 tmp[N],将指针后移。一边结束后,另一边剩余数字(已排序)填入列尾。相等数字,优先填前一个

稳定性,相等数字不变序。因为是从同一个原数组中取得的两个有序片段,相同数字,原本在前的继续在前

而快排不具有稳定性。因为数字频繁换位,只能通过额外区分解决

宏观上就是在 q[N] 从最小的片段开始,逐级获得更大的有序片段。随着有序片段越来越长,在 l o g n logn logn 次后完成排序

int q[N], tmp[N];
void merge_sort(int q[], int l, int r)
{if(l >= r)return;  //判断递归结束int mid = l + r >> 2;merge_sort(q, l, mid), merge_sort(q, mid + 1, r); //先排完小的,再排大的int k = 0, i = l, j = mid + 1;   //k是tmp的指针,i j是q的片段指针while(i <= mid && j <= r)if(q[i] <= q[j]) tmp[k++] = q[i++];else tmp[k++] = q[j++];   //双指针算法while(i <= mid) tmp[k++] = q[i++];while(j <= r) tmp[k++] = q[j++]; //剩余数列处理for(i = l, j = 0; i < r; i++, j++)q[i] = tmp[j];  //最后将tmp内容填回q中的原位
}

时间复杂度:归并和快排都是递归+线性比较,每层递归中,数据只扫描一次。其中快排根据数值不同,平均为O( n l o g n nlogn nlogn),最坏是O( n 2 n^2 n2)。而归并是按位置二分,一共分 l o g 2 n log_2n log2​n次,变成长度为1的数组,因此稳定在O( n l o g n nlogn nlogn)。

之所以快就是归功于二分法,相比线性方法可以说是降维打击。另外,时间复杂度忽略常系数

:代码长度、时间复杂度、空间复杂度都不是正相关的,需要自己取舍。


二分

一般是缩小范围用于查找等操作。假设数列是有序的

整数二分:根据查找的性质将集合一分为二,因为是整数数组,中点 mid 可有两种取法。举例:

n个整数组成的有序数列,其中有重复的数字。要求输入一个数,并输出这个数出现最左端和最右端的位置。若没有,输出-1 -1

int q[N], x; //省略输入,N>n。x是查找的数,假设数列是升序的
int l = 0, r = n - 1, mid;
while(l < r)
{mid = l + r >> 1;  //这里是否+1,原理和快排相同if(q[mid] >= x) r = mid;   //为了防止这一行因重合而死循环else l = mid + 1;
}   //第一次二分查找,通过判断等于或偏大,将范围从两边向 x 左端点缩小,最后l = mid + 1总能保证l r汇合且落在x边界上
if(q[l] != x) cout << "-1 -1" endl;
//l r已经汇合,一般单个元素查找到此结束了。整数数组在这里判断 x 是否存在,而小数数轴(比如算平方根)会输出一个近似值
else{cout << l << endl;l = 0, r = n - 1;while(l < r)   //求两个边界相当于查找两次,本质上查找条件也不同(因为取等于的方向不同){mid = l + r + 1 >> 1;if(q[mid] <= x) l = mid;else r = mid -1; //两种二分还是有区别的。这一次将范围向 x 右端点缩小,最后一步保证r落在右边界}cout << l << endl; //这里和上面一样,输出l 和 r 都行的
}

小数二分:一般出现在数学问题中,原理相同,而且不需要考虑边界问题,更简单,略

数据结构/算法笔记(1)-两种排序 二分查找相关推荐

  1. 【MySQL】MySQL 两种排序算法

    1.概述 原文:高性能MySQL一书.再抄的,找得快. 无论如何排序都是-一个成本很高的操作,所以从性能角度考虑,应尽可能避免排序或者尽可能避免对大量数据进行排序. 当不能使用索引生成排序结果的时候M ...

  2. mysql中两次排序_MySQL中的两种排序方式: index和filesort

    index :通过有序索引顺序扫描直接返回有序数据,不需要额外的排序,操作效率较高. filesort:通过对返回数据进行排序,filesort 并不代表通过磁盘文件排序,而是说明进行了一个排序操作, ...

  3. 【2020模拟考试T5】【PAT乙】1035 插入与归并 (25分) 两种排序的sort写法

    problem 1035 插入与归并 (25分) 根据维基百科的定义: 插入排序是迭代算法,逐一获得输入数据,逐步产生有序的输出序列.每步迭代中,算法从输入序列中取出一元素,将之插入有序序列中正确的位 ...

  4. 【字符串2】(删除公共字符、合法括号序列判断、两种排序方法、密码强度等级)

    字符串题集 1. 删除公共字符 题目描述 题目分析 C++代码 2. 合法括号序列判断 题目描述 题目分析 C++代码 3. 两种排序方法 题目描述 题目分析 C++代码 4. 密码强度等级 题目描述 ...

  5. day06-元组字典集合常用两种排序

    Day06-元组&字典&集合&常用两种排序 一.tuple元组 1.概述 和列表相似,本质上是一种有序的集合 元组和列表的不同之处: ​ a.列表:[ ] 元组:( ) ​ b ...

  6. iOS开发笔记-两种单例模式的写法

    iOS开发笔记-两种单例模式的写法 单例模式是开发中最常用的写法之一,iOS的单例模式有两种官方写法,如下: 不使用GCD #import "ServiceManager.h"st ...

  7. Java两种排序方式快慢比较

    2019独角兽企业重金招聘Python工程师标准>>> Java中List的排序方式有两种,现在我们测试下这两种排序方式的快慢吧,我们需要用到两个类, 一个是运行程序的Main类,另 ...

  8. c语言两种排序方法的组合,排列和组合算法的实现方法_C语言经典案例

    排列和组合算法是考查递归的常见算法,这两种算法能用递归简洁地实现. 本人在经过多次摸索和思考之后,总结如下,以供参考. 程序代码如下: #include #include char array[] = ...

  9. 按照姓名升序排序的代码_好程序员Java培训分享Java集合的两种排序方法

    好程序员Java培训分享Java集合的两种排序方法,Java集合的工具类Collections中提供了两种排序的方法,分别是: 1.Collections.sort(List list) 2.Coll ...

最新文章

  1. C9---include,编译
  2. 关于HashCode方法,可变对象和内存泄漏问题
  3. 2017级数据结构助教批改方案
  4. TortoiseSVN与VisualSVN Server搭建SVN版本控制系统
  5. 用 Go 构建一个区块链 -- Part 7: 网络
  6. 极速理解设计模式系列:22.状态模式(State Pattern)
  7. css绘制正方体_设计师仅使用CSS绘制了8个标志性X战警
  8. in会让mysql索引失效吗_mysql的in会不会让索引失效?
  9. docker jenkins 公钥_搭建 Jenkins 与 GitLab 的持续集成环境
  10. 计算机批处理英语,英语计算机词汇大全
  11. vs code配置python环境mac_Mac下搭建基于VSCode的Python开发环境
  12. 广技师计算机毕业都去哪,广东哪间大学的计算机专业比较好???
  13. 特斯拉首个中国工厂落户上海临港
  14. 爱因斯坦那颗大脑,究竟隐藏了什么
  15. rsync通过服务同步、linux日志、screen工具
  16. linux中LCD之framebuffer设备驱动
  17. sqlbulkcopy是覆盖式更新吗_酒店无线覆盖解决方案,一文了解清楚
  18. macbook使用共享屏幕实现VNC远程控制
  19. TX1、跨平台文件传输工具\使用记录
  20. 页面视觉稳定性之优化CLS

热门文章

  1. Bootstrap Navbar
  2. [01背包] 数字组合(01背包+求方案数)
  3. java基础~重写与重载
  4. 自媒体头条号如何发布操作内容
  5. oracle trunc 函数处理日期格式
  6. 中国眼影底漆行业市场供需与战略研究报告
  7. canva画图 图片居中裁剪_CSS3 object-fit:cover 剪裁图片尺寸适配div - 居中并裁剪图片...
  8. XXX.axf: Error: L6218E: Undefined symbol xxx (referred from xxxx.o).
  9. 解决vscode报错:command-line error: language modes specified are incompatible C/C++(1027)
  10. 使用姿势估计构建 姿势校正器