八大常见排序算法介绍

直接插入排序

算法思想

首先将第二个数与第一个数进行对比,如果第二个数比第一个数小,则将第二个数插入到第一个数之前,这样保证前两个数是有序的;
接下来将第三个数与前两个数对比,发现有比第三个数大的数即将第三个数插入到对应数的前面,这样一次插入可保证前三个数是有序的;
以此类推,将后面的i个数分别其前面的i-1个数进行对比,并将其插入到第一个比其大的数前面,最后即可完成排序。

时间空间复杂度及稳定性

  • T ( n ) = O ( n 2 ) T(n)=O(n^2) T(n)=O(n2)
  • S ( n ) = O ( 1 ) S(n)=O(1) S(n)=O(1)
  • 稳定

代码

void InsertSort(vector<int> v) {

    for (int i = 1; i < v.size();   i) {
        for (int j = 0; j < i;   j) {
            if (v[j] > v[i]) {
                int t = v[i];
                for (int k = i; k > j; --k) {
                    v[k] = v[k - 1];
                }
                v[j] = t;
            }
        }
    }
}

希尔排序

算法思想

希尔排序又称缩小增量排序,也属于一种插入排序算法,其基本思想是将要被排序的数列分成若干个子序列然后分别进行插入排序,待这些子序列排序完成后大序列就会基本有序,这时再对整个大序列进行一次直接插入排序;
其分散数列的原则一般是5-3-1,即先将大数列每隔5个取一个数,这样最终会形成5个子数列,将这5个子数列分别进行插入排序,然后将排序好的数列每隔3个取一个形成3个子数列,再对这三个子数列进行三次插入排序,最后,对整个基本有序的大数列进行一次插入排序达到排序整个数列的目的。

时间空间复杂度即稳定性

  • T ( n ) = O ( n 1.5 ) T(n)=O(n^{1.5}) T(n)=O(n1.5)
  • S ( n ) = O ( 1 ) S(n)=O(1) S(n)=O(1)
  • 不稳定

代码

void ShellSort(vector<int> v) {
    int d[3] = {5, 3, 1};
    for (int i = 0; i < 3;   i) {
        ShellInsert(v, d[i]);
    }
    show(v);
}


void ShellInsert(vector<int> &v, int d) {
    for (int l = 0; l < d;   l) {
        for (int i = l   1; i < v.size(); i  = d) {
            for (int j = l; j < i; j  = d) {
                if (v[i] < v[j]) {
                   int t=v[i];
                   for(int k=i;k>j;i-=d){
                      v[k]=v[k-d];
                      }
                    v[j]=t;
                }
            }
        }
    }
}

冒泡排序

算法思想

冒泡排序的主要思想是将大的数向下“沉”,将小的数向上“气泡”,具体过程:
首先将第一个数与第二个数进行对比,若第二个数小于第一个数,则将第一个数与第二个数交换,然后比较第二个数和第三个数,如果第二个数大于第三个数,则将其对换,最后的结果是将数列中最大的一个数换到数列的最后一位。
然后再对前n-1个数进行相同的过程,结果是将倒数第二大的数放在倒数第二位。
以此类推,经历n-1次后所有数列将会有序。

时间空间复杂度及稳定性

  • T ( n ) = O ( n 2 ) T(n)=O(n^2) T(n)=O(n2)
  • S ( n ) = O ( 1 ) S(n)=O(1) S(n)=O(1)
  • 稳定

代码


void BubbleSort(vector<int> v) {

    for (int i = 0; i < v.size();   i) {
        int flag = 1;
        for (int j = 0; j < v.size() - i && j < v.size() - 1;   j) {
            if (v[j] > v[j   1]) {
                int t;
                t = v[j];
                v[j] = v[j   1];
                v[j   1] = t;
                flag = 0;
            }
        }

        if (flag == 1) {//说明已经有序了
            break;
        }
    

    show(v);
}

快速排序

算法思想

快速排序是对冒泡排序的一种改进,其基本思路是通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。

时间空间复杂度及稳定性

  • T ( n ) = O ( n l o g 2 n ) T(n)=O(nlog_2n) T(n)=O(nlog2n)
  • S ( n ) = O ( l o g 2 n ) S(n)=O(log_2n) S(n)=O(log2n)
  • 不稳定

代码


void QuickSort(vector<int> v) {
    QSort(v, 0, v.size() - 1);
    show(v);
}

void QSort(vector<int> &v, int low, int high) {

    if (low >= high) {
        return;
    }
    int t = Partition(v, low, high);
    QSort(v, low, t - 1);
    QSort(v, t   1, high);
}

int Partition(vector<int> &v, int low, int high) {
    int pivotkey;
    pivotkey = v[low];

    while (low < high) {
        while (low < high && v[high] >= pivotkey) {
            --high;
        }
        int t;
        t = v[low];
        v[low] = v[high];
        v[high] = t;

        while (low < high && v[low] <= pivotkey) {
              low;
        }
        t = v[low];
        v[low] = v[high];
        v[high] = t;
    }

    return low;
}

选择排序

算法思想

选择排序的思路是首先找到序列中的最小数,将其放在第一位,然后找到第二小的数将其放在第二位,以此类推,最终将所有第i小的数放在第i位从而达到排序目的。

时间空间复杂度及稳定性

  • S ( n ) = O ( 1 ) S(n)=O(1) S(n)=O(1)
  • T ( n ) = O ( n 2 ) T(n)=O(n^2) T(n)=O(n2)
  • 不稳定

代码


void SelectSort(vector<int> v) {
    for (int i = 0; i < v.size();   i) {
        int min;
        min = i;
        for (int j = i   1; j < v.size();   j) {
            if (v[j] < v[min]) {
                min = j;
            }
        }
        int t;
        t = v[min];
        v[min] = v[i];
        v[i] = t;
    }
    show(v);
}

堆排序

算法思想

堆排序的主要思路是先将所要排序的数列看做是一颗完全二叉树并建立大顶堆,然后将堆顶元素放在堆的最后一位,然后再调整该二叉树为大顶堆,然后再将堆顶放在二叉树的最后一位,调整二叉树为大顶堆,重复这一过程直至完成排序。

时间空间复杂度及稳定性

  • T ( n ) = O ( n l o g 2 n ) T(n)=O(nlog_2n) T(n)=O(nlog2n)
  • S ( n ) = O ( 1 ) S(n)=O(1) S(n)=O(1)
  • 不稳定

代码


void HeapSort(vector<int> v) {

    int size = v.size();
    v.push_back(0);
    for (int k = v.size(); k > 0; --k) {
        v[k] = v[k - 1];
    }
    //建堆
    for (int i = size / 2; i > 0; --i) {
        HeapAdjust(v, i, size);
    }

    for (int j = size; j > 1; --j) {
        int t;
        t = v[1];
        v[1] = v[j];
        v[j] = t;
        HeapAdjust(v, 1, j - 1);
    }
    for (int i = 1; i < v.size();   i) {
        cout << v[i] << " ";
    }
    cout << endl;
}

void HeapAdjust(vector<int> &v, int s, int m) {
    /*
     * 已知v[s..m]除v[s]之外均满足堆的定义,本函数调整v[s],使得v[s..m]成为一个小顶堆
     */

    int rc;
    rc = v[s];
    for (int i = 2 * s; i <= m; i = 2 * i) {
        if (i < m && v[i] < v[i   1]) {
            i  ;//i为较大数据的下标
        }
        if (rc >= v[i]) {
            break;
        }

        v[s] = v[i];
        s = i;
    }
    v[s] = rc;
}

归并排序

算法思想

归并排序的主要思路是将索要排序数列看做若干个有序的小数列,因为将两个有序数列合并之后所得数列还是有序数列,所以经过不断合并,最后可将数列排为有序。

时间空间复杂度及稳定性

  • T ( n ) = O ( n l o g 2 n ) T(n)=O(nlog_2n) T(n)=O(nlog2n)
  • S ( n ) = O ( n ) S(n)=O(n) S(n)=O(n)
  • 稳定

代码


void MSort(vector<int> v) {


    vector<int> h;
    h = v;

    int start, seg;


    for (seg = 1; seg < v.size(); seg *= 2) {
        int k = 0;
        for (start = 0; start < v.size(); start = start   seg * 2) {
            int end;
            end = start   seg;
            int low = start;
            while (low < start   seg && end < start   seg   seg && low < v.size() && end < v.size()) {
                if (v[low] <= v[end]) {
                    h[k  ] = v[low];
                    low  ;
                } else {
                    h[k  ] = v[end];
                    end  ;
                }
            }

            while (low < start   seg && low < v.size()) {
                h[k  ] = v[low  ];
            }
            while (end < start   seg   seg && end < v.size()) {
                h[k  ] = v[end  ];
            }

        }

        v = h;
    }
    show(v);

}

基数排序

算法思想

基数排序需要经历d次,d为所要排序数列中位数最多的数的位数,其过程是首先根据数列中数的个位的数值将所有数入09这10个队列,然后从09将元素依次出队,然后再根据十位元素的数值再次入队,然后出队,以此类推重复d次,最终即可完成排序。

时间空间复杂度及稳定性

  • T ( n ) = O ( d ∗ n ) T(n)=O(d*n) T(n)=O(dn) d为排序数中最大数的位数
  • S ( n ) = O ( n ) S(n)=O(n) S(n)=O(n)
  • 稳定

代码


void radixSort(vector<int> v) {

    int d = GetMaxBit(v);

    int *count = new int[10];
    queue<int> q[10];

    int radix = 1;
    for (int i = 0; i < d;   i) {
        for (int j = 0; j < v.size();   j) {
            int t;
            t = (v[j] / radix) % 10;
            q[t].push(v[j]);
        }

        int p = 0;
        for (int k = 0; k < 10;   k) {
            while (!q[k].empty()) {
                v[p  ] = q[k].front();
                q[k].pop();
            }
        }
        radix *= 10;
    }
    show(v);

}

复杂度总结

排序方法时间复杂度空间复杂度
直接插入排序 T ( n ) = O ( n 2 ) T(n)=O(n^2) T(n)=O(n2) S ( n ) = O ( 1 ) S(n)=O(1) S(n)=O(1)
希尔排序 T ( n ) = O ( n 1.5 ) T(n)=O(n^{1.5}) T(n)=O(n1.5) S ( n ) = O ( 1 ) S(n)=O(1) S(n)=O(1)
冒泡排序 T ( n ) = O ( n 2 ) T(n)=O(n^2) T(n)=O(n2) S ( n ) = O ( 1 ) S(n)=O(1) S(n)=O(1)
快速排序 T ( n ) = O ( n l o g 2 n ) T(n)=O(nlog_2n) T(n)=O(nlog2n) S ( n ) = O ( l o g 2 n ) S(n)=O(log_2n) S(n)=O(log2n)
选择排序 S ( n ) = O ( 1 ) S(n)=O(1) S(n)=O(1) T ( n ) = O ( n 2 ) T(n)=O(n^2) T(n)=O(n2)
堆排序 T ( n ) = O ( n l o g 2 n ) T(n)=O(nlog_2n) T(n)=O(nlog2n) S ( n ) = O ( 1 ) S(n)=O(1) S(n)=O(1)
归并排序 T ( n ) = O ( n l o g 2 n ) T(n)=O(nlog_2n) T(n)=O(nlog2n) S ( n ) = O ( n ) S(n)=O(n) S(n)=O(n)
基数排序 T ( n ) = O ( d ∗ n ) T(n)=O(d*n) T(n)=O(dn) d为排序数中最大数的位数 S ( n ) = O ( n ) S(n)=O(n) S(n)=O(n)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
十种排序算法介绍 转自:matrix67 今天我正式开始挄照我癿目彔写我癿 oi 心得了。我要把我所有学到癿 oi 知识传给以后千千万万癿 oier。以前写过 癿一些东西丌重复写了,但我最后将会重新整理,使乊成为一个完整癿教程。 ???? 挄照我癿目彔,讲仸何东西乊前我都会先介绍旪间复杂度癿相关知识,以后劢丌劢就会扯到这个东西。这个 已经写过了,你可以在这里看到那篇又臭又长癿文章。在讲排序算法癿过程中,我们将始终围绕旪间复杂度癿内容 迚行说明。 ???? 我把这篇文章称乊为“仍零开始学算法”,因为排序算法是最基础癿算法介绍算法旪仍各种排序算法入手是 最好丌过癿了。 ???? 给出 n 个数,怎样将它们仍小到大排序?下面一口气讲三种常用癿算法,它们是最简单癿、最显然癿、最容 易想到癿。选择排序(selection sort)是说,每次仍数列中找出一个最小癿数放到最前面来,再仍剩下癿 n-1个数 中选择一个最小癿,丌断做下去。揑入排序(insertion sort)是,每次仍数列中取一个还没有取出过癿数,幵挄照 大小关系揑入到已经取出癿数中使得已经取出癿数仌然有序。冒泡排序(bubble sort)分为若干趟迚行,每一趟排 序仍前往后比较每两个相邻癿元素癿大小(因此一趟排序要比较 n-1对位置相邻癿数)幵在每次发现前面癿那个数 比紧接它 后癿数大旪交换位置;迚行足够多趟直到某一趟跑完后发现这一趟没有迚行仸何交换操作(最坏情况下 要跑 n-1趟,这种情况在最小癿数位亍给定数列癿最后面旪 发生) 。事实上,在第一趟冒泡结束后,最后面那个数 肯定是最大癿了,亍是第二次叧需要对前面 n-1个数排序,这又将把这 n-1个数中最小癿数放到整个数列 癿倒数 第二个位置。这样下去,冒泡排序第 i 趟结束后后面 i 个数都已经到位了,第 i+1 趟实际上叧考虑前 n-i 个数(需 要癿比较次数比前面所说癿 n-1要 小) 。这相当亍用数学归纳法证明了冒泡排序癿正确性:实质不选择排序相同。 上面癿三个算法描述可能有点模糊了,没明白癿话网上找资料,代码和劢画演示遍地 都是。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值