P1177 【模板】快速排序

不用说,连题目上都标了是一道模板,那今天就来对能用到的许多排序方式进行一个总结:

选择排序

选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到全部待排序的数据元素排完。 选择排序是不稳定的排序方法。(稳定不稳定最后再讲)

这是选择排序的思想:每一趟在n-i+1(i=1,2,3…,n-1)个记录中选取关键字最小的记录与第i个记录交换,并作为有序序列中的第i个记录。

例如:
待排序列: 43,65,4,23,6,98,2,65,7,79
第一趟: 2,65,4,23,6,98,43,65,7,79
第二趟: 2,4,65,23,6,98,43,65,7,79
第三趟: 2,4,6,23,65,98,43,65,7,79
第四趟: 2,4,6,7,43,65,98,65,23,79
第五趟: 2,4,6,7,23,65,98,65,43,79
第六趟: 2,4,6,7,23,43,98,65,65,79
第七趟: 2,4,6,7,23,43,65,98,65,79
第八趟: 2,4,6,7,23,43,65,65,98,79
第九趟: 2,4,6,7,23,43,65,65,79,98

贴个代码:

#include <iostream>
using namespace std;
void SelectSort(int a[], int n) //选择排序
{
int mix, temp;
for (int i = ; i < n - ; i++) //每次循环数组,找出最小的元素,放在前面,前面的即为排序好的
{
mix = i; //假设最小元素的下标 for(int j=i+1;j<n;j++)
//将上面假设的最小元素与数组比较,交换出最小的元素的下标
if (a[j] < a[mix])
mix = j; //若数组中真的有比假设的元素还小,就交换
if (i != mix)
{
temp = a[i];
a[i] = a[mix];
a[mix] = temp;
}
}
}
int main()
{
int a[] = {, , , , , , , , , };
SelectSort(a, );
for (int i = ; i < ; i++)
cout << a[i] << " ";
cout << endl;
return ;
}

很明显,我们用到了两个嵌套的循环,所以时间复杂度就是o(n^2)的

然鹅。。。。正常人都会觉得这算法太慢了吧!!!!!!

所以我们来讲个好一点的;

冒泡排序(也是我比较喜欢的一种)

具体思路是什么呢:

冒泡排序的基本思想为:
一趟冒泡排序的过程为:首先将第一个记录的关键字和第二个记录的关键字进行比较,若为逆序,则将两个记录交换之,然后比较第二个记录的关键字和第三个记录的关键字,依次类推,直至第n-1个记录和第n个记录的关键字进行过比较为止;
在冒泡排序的过程中,关键字较小的记录好比肥宅快乐水(雾)的气泡逐趟向上漂浮,而关键字较大的记录好比石头往下沉,每一趟有一块“最大”的石头沉到水底。

还是上面那个数
待排序列:43, 65, 4, 23, 6, 98, 2, 65, 7, 79
第一趟: 43, 4,23,6,65,2,65,7,79,98
第二趟: 4,23,6,43,2,65,7,65,79,98
第三趟: 4,6,23,2,43,7,65,65,79,98
第四趟: 4,6,2,23,7,43,65,65,79,98
第五趟: 4,2,6,7,23,43,65,65,79,98
第六趟: 2,4,6,7,23,43,65,65,79,98

冒泡排序的时间复杂度为:O(n^2),空间复杂度为O(1)

冒泡排序是稳定的;

好吧其实这俩货时间复杂度是一样的,但是我还是喜欢用冒泡QAQ

贴一下代码吧

#include <iostream>
#include <algorithm>
using namespace std;
void bubleSort(int a[], int n) //冒泡排序
{
//运用两个for循环,每次取出一个元素跟数组的其它元素比较,将最大的元素排到最后
for (int i = ; i < n - ; i++)
{ //外循环一次,就排好一个数,并放在后面,所以比较前面n-i-1个元素即可
for (int j = ; j < n - i - ; j++)
{
if (a[j] > a[j + ])
{
swap(a[j],a[j+]);//swap其实和之前那个temp的作用是一样的,就是交换一下数字而已
}
}
}
}
int main()
{
int a[] = {, , , , , , , , , };
bubleSort(a, );
for (int i = ; i < ; i++)
cout << a[i] << " ";
cout << endl;
return ;
}

冒泡排序其实还有一个挺重要的用处,就是找一堆数里头的最大数和最小数,其实就是用的冒泡的方法

for(int i=;i<=n;i++)
{
if(a[i]>Max)
Max=a[i];
}

还有一个很重要的排序方式

快速排序

一听就很快啊有没有(雾)

快速排序的思想是找一个基准数,比基准数小的扔到左边去,大的扔到右边去(升序排列时)

听起来挺简单的吧,,,代码实现可能有一点点复杂,慢慢看

代码如下

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
int findPos(int a[], int low, int high)
{
//将小于t的元素赶到t的左边,大于t的元素赶到t的右边
int t = a[low];
while (low < high)
{
while (low < high && a[high] >= t)
high--;
a[low] = a[high];
while (low < high && a[low] <= t)
low++;
a[high] = a[low];
}
a[low] = t; //返回此时t在数组中的位置
return low;
} //在数组中找一个元素,对于大于该元素和小于该元素的两个数组进行再排序,
//再对两个数组分为4个数组,再排序,直到最后每组只剩下一个元素为止
void quickSort(int a[], int low, int high) //快速排序
{
if (low > high)
return;
int pos = findPos(a, low, high);
quickSort(a, low, pos - );
quickSort(a, pos + , high);
}
int main()
{
int, n, a[];
scanf("%d", &n);
for (int i = ; i <= n; ++i)
scanf("%d", &a[i]);
quickSort(a, , sizeof(a));
for (int i = ; i < ; i++)
cout << a[i] << " ";
cout << endl;
return ;
}

我们再来看看归并排序这个东西

归并排序(最不常用但是是实打实的快的算法)

将两个的有序数列合并成一个有序数列,我们称之为"归并"。
归并排序(Merge Sort)就是利用归并思想对数列进行排序。根据具体的实现,归并排序包括"从上往下"和"从下往上"2种方式。

基本思想:先将整个数组分成两个部分,分别将两个部分排好序,然后将两个排好序的数组O(n)合并成一个数组。
我们将问题分为两个阶段:分、治

对于每个长度> 1的区间,拆成两个[l, mid]区间
和[mid + 1, r]区间
直接递归下去

这样的话就可以一直递归直到只剩下一个数的时候,就分完了

我们认为在处理区间[l,r]时,已经有[l,mid]和[mid+1,r]内分别有序,这一次的操作就是合并两个有序序列,成为一个新的长有序序列。
用两个指针分别指向左右分别走到哪了即可

举一个例子吧,比如我们要合并这两个数组(模拟一下合并过程)

135

246

显然你肯定不能把246直接接到135后面对吧,这个时候我们建两个指针S1=1和S2=1(我的习惯是下标从1开始)

然后干这样一件事先比较a[s1]和b[s2]的大小,这里1更小一点,

所以

c[i]=b[s2];

S2++;

这里其实就是用两个指针分别从要合并的两个数组的头元素指起,如果元素被合并,那么就指针++,直到两个数组的指针都指完为止,就是这一块

算法的时间复杂度就是O(nlogN)

然后再看看堆排()

堆的讲解点这里QWQ

堆排吧,其实就是利用一个大根堆或者是小根堆来对一组数据进行合并和动态维护其顺序。

其代码本身并没有与堆的板子有太多差别,而是完全按照加入元素弹出元素那些函数来维护的,改一改就能交啦

自己黈自己(QWQ还是gh神仙给我纠正手写堆)

#include <iostream>
#include <queue>
#include <algorithm>
#include <cstdio>
using namespace std;
int n, a, b, Heap[], cnt = ;
inline void add(int x)
{
Heap[++cnt] = x;
int now = cnt;
while (now!=)
{
if (Heap[now] < Heap[now >> ])
swap(Heap[now], Heap[now >> ]),now>>=;
else
break;
}
}
inline void pop()
{
printf("%d\n", Heap[]);
Heap[] = Heap[cnt--];
int root = ;
while (root << <= cnt)
{
int son;
if ((root << ) + > cnt ||
Heap[root << ] < Heap[(root << ) + ])
{
son = root << ;
}
else
son = (root << ) + ;
if (Heap[son] > Heap[root])
break;
swap(Heap[root], Heap[son]);
root = son;
}
}
int main()
{
scanf("%d", &n);
for (int i = ; i <= n; ++i)
{
scanf("%d", &b);
add(b);
}
while(n)
{
pop();
n--;
}
return ;
}

值得注意的是,如果把一整个堆按照下标顺序输出去,往往是无序的

原因是这个:

堆是一个完全二叉树,所以所谓大小关系仅仅是一个树根和他的两个智障儿子的关系,而不是说按顺序输出一定是有序数列,

堆排序能完成排序,其实是依靠每一次都弹出堆顶元素,然后进行动态维护,所以最终输出的数列是一个有序数列。

上面是堆排,下面是快排,由此可见堆排的确是很快的

最后一个(超级无敌变态的做法)

c++自带STL

其实就是sort函数

头文件是#include <algorithm>

Sort函数有三个参数:

(1)第一个是要排序的数组的起始地址。
(2)第二个是结束的地址(最后一位要排序的地址的下一地址)
(3)第三个参数是排序的方法,可以是从大到小也可是从小到大,还可以不写第三个参数,此时默认的排序方法是从小到大排序。

其实还是挺简单的吧。。。。。。。

主要是排序能够练习对于数组的运用,这是培养思维和能力的好方法,至于考场上嘛,,,,,,还是sort好啊(雾

最后,我们贴一下AC代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
int findPos(int a[], int low, int high)
{
//将小于t的元素赶到t的左边,大于t的元素赶到t的右边
int t = a[low];
while (low < high)
{
while (low < high && a[high] >= t)
high--;
a[low] = a[high];
while (low < high && a[low] <= t)
low++;
a[high] = a[low];
}
a[low] = t; //返回此时t在数组中的位置
return low;
} //在数组中找一个元素,对于大于该元素和小于该元素的两个数组进行再排序,
//再对两个数组分为4个数组,再排序,直到最后每组只剩下一个元素为止
void quickSort(int a[], int low, int high) //快速排序
{
if (low > high)
return;
int pos = findPos(a, low, high);
quickSort(a, low, pos - );
quickSort(a, pos + , high);
}
int main()
{
int n, a[];
scanf("%d", &n);
for (int i = ; i <= n; ++i)
scanf("%d", &a[i]);
quickSort(a, , n);
for (int i = ; i <= n; i++)
cout << a[i] << " ";
cout << endl;
return ;
}

P1177 【模板】快速排序(学完归并和堆排之后的二更)的更多相关文章

  1. Golang入门(2):一天学完GO的基本语法

    摘要 在配置好环境之后,要研究的就是这个语言的语法了.在这篇文章中,作者希望可以简单的介绍一下Golang的各种语法,并与C和Java作一些简单的对比以加深记忆.因为这篇文章只是入门Golang的第二 ...

  2. 在w3cschool学完html,css,javascript,jquery以后,还是不会做前端怎么办?

    w3cschool是一个非盈利性的在线技术学习网站,提供按W3C标准编写的基础教程.完整的看完w3cschool上面的手册,可以基本掌握编程语法.基础性的东西通常都会比较零散,因此,在学习一段时间后, ...

  3. 7天学完Java基础之0/7

    笔记-7天学完Java基础之0/7 1.常用命令提示符(cmd) 启动:Win+R,输入cmd​

  4. python 快排,堆排,归并

    #归并排序 def mergeSort(a,L,R) :     if(L>=R) :         return     mid=((L+R)>>1)     mergeSort ...

  5. 学完微型服务器(Tomcat)对其工作流程的理解,自己着手写个简单的tomcat

    学完微型服务器(Tomcat)对其工作流程的理解,自己着手写个简单的tomcat 2019-05-09   19:28:42 注:项目(MyEclipse)创建的时候选择:Web Service Pr ...

  6. 零基础学完Python的7大就业方向,哪个赚钱多?

    “ 我想学 Python,但是学完 Python 后都能干啥 ?” “ 现在学 Python,哪个方向最简单?哪个方向最吃香 ?” “ …… ” 相信不少 Python 的初学者,都会遇到上面的这些问 ...

  7. Golang入门(3):一天学完GO的进阶语法

    摘要 在上一篇文章中,我们聊了聊Golang中的一些基础的语法,如变量的定义.条件语句.循环语句等等.他们和其他语言很相似,我们只需要看一看它们之间的区别,就差不多可以掌握了,所以作者称它们为&quo ...

  8. 0基础如何更快速入门Linux系统?学完Linux有哪些就业方向?

    Linux系统是使用Linux内核及开源自由软件组成的一套操作系统,是一种类UNIX系统,其内核在1991年10月5日由林纳斯·托瓦兹首次发布. 它的主要特性:Linux文件一切皆文件.完全开源免费. ...

  9. 3分钟学完Python,直接从入门到精通

    作为帅气小编,我已经把python一些模块的甩在这儿了qwq,只要你拿到这些干货,包你玩转python,直接冲向"大佬"的段位,如果已经学了C或者C++或者说如果你需要你的一段关键 ...

随机推荐

  1. 基础知识:if判断、while循环、for循环

    今日学习内容                   1.if 判断(流程控制的一种) 写重复的代码是程序员最不耻的行为,所以我们需要while循环和for循环 ,^_^!                 ...

  2. 简述Servlet的基本概念

    Servlet的基本概念 Servlet的概念 http协议作用于客户端-服务端.由客户端发送请求(Request),服务器端接收到数据之后,向客户端发送响应(Response),这就是请求-响应模式 ...

  3. 学JAVA第十五天,方法重载及构造方法进一步了解

    由于星期五生病了,所以就没写.今天上课,又来写了!!! 先来说方法的重载. 方法的重载就是有两个方法的方法名相同,但参数不一致,参数个数不一致,或参数的类型不一样. package pkg9;publ ...

  4. 关于单链表的增删改查方法的递归实现(JAVA语言实现)

    因为在学习数据结构,准备把java的集合框架底层源码,好好的过一遍,所以先按照自己的想法把单链表的类给写出来了; 写该类的目的: 1.练习递归 2.为深入理解java集合框架底层源码打好基础 学习的视 ...

  5. react+redux+Instagram

    项目地址:https://github.com/xiaoyuqing/react-redux-instagram,喜欢的话动动手指点点赞^-^ 1.初始化项目 IndexRoute是默认路由 2.增加 ...

  6. K3日志定时备份

    K3日志超过5万条以后,每次用户登陆后,系统都会提示日志太多.但是日志又不能随意删除,所以需要做个数据库定时任务,定时把日志转移到备份表. declare @dt datetime;; SELECT ...

  7. 使用Android服务,实现报警管理器和广播接收器

    介绍 几乎在所有平台上都有很多进程运行背景,它们被称为服务.可能在Android平台中有一些服务可以执行长时间运行的操作,这些操作在处理时不需要用户交互. 在本文中,借助预定义的Android警报服务 ...

  8. Kubernetes入门-集群安装

    Kubernetes是谷歌开源的容器集群编排平台,是一个完备的分布式系统支撑平台,为容器化应用提供部署运行.资源调度.服务发现和动态伸缩等一系列完整功能,具有强大的故障发现和自我修复机制.服务滚动升级 ...

  9. C#的扩展方法(this)

    先在StringLibrary类中定义一个静态方法,如下: public static class StringLibrary { //第一个参数指定该方法作用于哪个类型,并且该参数以 this 修饰 ...

  10. lua_local变量在new时不会被清空

    前言 我的运行环境 Lua5.3 按照我们以往的Java或C#编程经验,如果一个class被new,那么这个class中所有成员变量的值都是默值或是构造函数中赋的值,但在Lua中的local变量却并不 ...