学习笔记 | 几种常见的基本和高效排序算法

参考资料:《C++数据结构与算法》(第4版)


01 题目感知…

题目:分别采用以下3种排序方法,对数组[5,2,3,8,1]按升序排序。

方法一:【选择排序】
include<iostream>
using namespace std;

void selection(int *num,int n ) {
    int i, j, least, temp;
    for (i = 0; i < n; i++) {
        least = i;
        for (j = i + 1; j < n; j++)
            if (num[j] < num[least])
                least = j;
        if (least != i)
            swap(num[j - 1], num[j]);
    }
    
    int main() {
        int num[5] = {5, 2, 3, 8, 1};
        selection(num, 5);
        for (int i = 0; i < 5; i++)
            cout << num[i];
    }
方法二:【冒泡排序】

01 从前往后冒

#include<iostream>
using namespace std;

//从前往后冒
void bubblesortFromhead(int *num,int n ) {
    int i, j, temp;
    for (i = 0; i < n - 1; i++)
        for (j = 0; j < n - 1 - i; j++)//最大的放在最后一个
            if (num[j + 1] < num[j])//谁小谁往前
                swap(num[j], num[j + 1]);
}

int main(){
    int num[5]={5,2,3,8,1};
    bubblesortFromhead(num,5);
    for(int i=0;i<5;i++)
        cout << num[i];
}

02 从后往前冒

#include<iostream>
using namespace std;

//从后往前冒
void bubblesortFromback(int *num,int n ) {
    int i, j, temp;
    for (i = 0; i < n - 1; i++)
        for (j = n - 1; j > i; j--)
            if (num[j - 1] > num[j]) {
                swap(num[j-1],num[j]);
            }
}

int main(){
    int num[5]={5,2,3,8,1};
    bubblesortFromback(num,5);
    for(int i=0;i<5;i++)
        cout << num[i];
}
方法三:【插入排序】
#include<iostream>
using namespace std;

void insertionsort(int *num,int n ) {
    int i, j, temp;
    for (i = 1; i < n ; i++) {
        temp = num[i];
        for (j = i; j > 0 && temp < num[j - 1]; j--) {//到0位置或前面小停止
            num[j] = num[j - 1];
            num[j-1] = temp;
        }
    }
}

int main(){
    int num[5]={5,2,3,8,1};
    insertionsort(num,5);
    for(int i=0;i<5;i++)
        cout << num[i];
}

02 方法剖析…

PART one:基本的排序方法

1.选择排序

选择排序就是先找到位置不合适的元素,再把它放在其最终的合适位置上,很明确地直接交换数组元素。

(1)算法

如N个数升序排列:
step1:0到N-1位置找最小值(注意是找到最小的再交换,不是找到了小的就交换)和第0位置交换。
step2:1到N-1位置找最小值,和第1位置交换。
···
stepN-1:N-2到N-1位置找最小值,和第N-2位置交换。

伪代码如下:

selectionsort(data[],n)
  for i=0 到 n-2//n-2s是最后一个i值,因为如果除最后一个元素之外的所有元素都放在合适的位置上,那么第n个元素(位于n-1位置上)就一定是最大的
    找出元素data[i],…,data[n-1]中的最小元素;
    将其与data[i]交换;
(2)复杂度

时间复杂度:O(N^{2})
额外空间复杂度:O(1)

(3)优缺点

优点:赋值次数少。这次其它算法无法比拟的。

2.冒泡排序

(1)算法

如N个数升序排列:
①从前往后冒泡
round1
step1:0到1位置哪个大,谁跑后面去。
step2:1到2位置哪个大,谁跑后面去。
···
stepN-1:N-2到N-1位置哪个大,谁跑后面去。

round2
step1:0到1位置哪个大,谁跑后面去。
step2:1到2位置哪个大,谁跑后面去。
···
stepN-2:N-3到N-2位置哪个大,谁跑后面去。
.
.
.
roundN-1
step1:0到1位置哪个大,谁跑后面去。

伪代码如下:

bubblesort(data[],n)
  for i=0 到 n-2
    for j=0 往上到 n-2-i
      如果两者逆序,则交换位置j和位置j-1的元素

②从后往前冒泡
round1
step1:N-1到N-2位置哪个小,谁跑前面去。
step2:N-2到N-3位置哪个小,谁跑前面去。
···
stepN-1:1到0位置哪个小,谁跑前前去。

round2
step1:N-2到N-3位置哪个小,谁跑前面去。
step2:N-3到N-4位置哪个小,谁跑前面去。
···
stepN-2:1到0位置哪个小,谁跑前面去。
.
.
.
roundN-1
step1:1到0位置哪个小,谁跑前面去。

伪代码如下:

bubblesort(data[],n)
  for i=0 到 n-2
    for j=n-1 往下到 j+1
      如果两者逆序,则交换位置j和位置j-1的元素
(2)复杂度

时间复杂度:O(N^{2})
额外空间复杂度:O(1)

(3)优缺点

缺点:元素需要一步步地向上冒泡知道数组的顶部,这是非常费时的。

3.插入排序

(1)算法

如N个数升序排列:
使0到i(i=1,2...N-1)位置有序。
step1:从1位置往前看,前面大就交换,否则停止。
step2:到0位置或前面小停止。
这里的时间复杂度与数据的具体状况有关,这是与前两者排序的区别。插入排序在最好的情况下只需要n-1次比较,但是在平均情况和最坏情况下,插入排序需要n^2次比较。

伪代码如下:

insertionsort(data[],n)
  for i=1 到 n-1
    将大于data[i]的所有元素data[j]都移动有一个位置,将data[i]放在合适的位置上
(2)复杂度

时间复杂度:O(N^{2})(算法流程按照最差情况来估计时间复杂度,但是做实验一定比前两者好。)
额外空间复杂度:O(1)
【拓展】对有序数列查找某元素——二分法
在一个有序数组中,找某个数是否存在
在一个有序数组中,找>=某个数最左侧的位置
局部最小值问题
如N个升序排列的数,要找n:
时间复杂度:O(\log_2{N})。多少次才能分成只有一个数。

(3)优缺点

优点:只有需要时才会对数组进行排序。如果数组已经排好序,就不会再对数据进行移动。


性能差异鼓励人们寻找性能函数是nlnn的算法

PART two:高效的排序方法

4.快速排序

(1)算法

快速排序本身是递归的,因为它在划分的每个层次上都将快速排序应用到数组的两个子数组上。

伪代码如下:

quicksort2 (array[])
    if  length(array)>10
        将arrary划分为子数组subarry1和subarry2
        quicksort(subarray1);
        quicksort(subarray2); 
  else insertionsort(array);//对于少于30个数据项的小数组来说,插入排序比快速排序更加有效

最简单的策略之一是选择数组的第一个元素作为边界值。一种更加谨慎的办法就是选取位于数组中间位置的元素作为边界值。

(2)复杂度
(3)优缺点

5.归并排序

快速排序最大的问题是它在最坏的情况下复杂度是O(n^2)(很难控制划分的过程)。另一个策略是使划分尽可能简单,着重于合并两个已经排好序的数组。

归并排序的主要过程是将多个已经排好序的子数组合并一个排好序的数组。然而这些子数组必须先排好序,合并方法是合并更小的、已排好序的子数组。这种算法的本身也是递归的。

伪代码如下:

mergesort (data[],first,last)
    if first<last
        mid=(first+last)/2;
        mergesort(data,first,mid);
        merge(data,mid+1,last);
        merge(data,first,last);
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353

推荐阅读更多精彩内容