数据结构九大排序方法总结(C++实现)

复习数据结构时,仿照王道数据结构考研复习指导,复现九大排序算法,包括插入排序(直接插入排序,折半插入排序,希尔排序),交换排序(冒泡排序,快速排序),选择排序(简单选择排序,堆排序),归并排序基数排序

以下算法均采用C++实现。

插入排序

直接插入排序

直接插入排序是每次将一个待排序的记录插入已经排好序的子序列,直到全部记录插入完成。
即:1.从前面的有序子表中查找出待插入元素应该被插入的位置;2.给插入位置腾出空间,将待插入元素复制到表中的插入位置

void InsertSort1(int A[], int n)
{
    int i, j;
    for (i = 2; i <= n; i++)
    {
        if (A[i] < A[i - 1])
        {
            //方法一
            // A[0] = A[i]; // A[0]为哨兵
            // for (j = i - 1; A[j] > A[0]; j--) //元素后移,寻找插入位置
            // {
            //     A[j + 1] = A[j];
            // }
            // A[j + 1] = A[0];

            //方法二
            A[0] = A[i];
            j = i - 1;
            do
            {
                A[j + 1] = A[j];
                j--;
            } while (j >= 1 && A[j] > A[0]);
            A[j + 1] = A[0];
        }
    }
}

其中,A[0]为哨兵元素。
直接插入排序:时间复杂度O(n2),空间复杂度O(1),稳定的排序算法。

折半插入排序

折半插入排序减少比较元素的次数。

void InsertSort2(int A[], int n)
{
    int i, j;
    for (i = 2; i <= n; i++)
    {
        A[0] = A[i];
        int l = 1, r = i - 1;
        while (l <= r) //先折半查找出元素的待插入位置,然后统一地移动待插入位置之后的所有元素
        {
            int mid = l + (r - l) / 2;
            if (A[0] < A[mid])
                r = mid - 1;
            else
                l = mid + 1;
        }
        for (j = i - 1; j >= r + 1; j--)
        {
            A[j + 1] = A[j];
        }
        A[r + 1] = A[0];
    }
}

折半插入排序时间复杂度仍为O(n2),是一种稳定的排序算法。

希尔排序

希尔排序又称为缩小增量排序,即把相隔某个增量的记录组成一个子表,对各个子表分别进行直接插入排序,当整个表中的元素已经“基本有序”时,再对全体记录进行一次直接插入排序。

void ShellSort(int A[], int n)
{
    int i, j, dk;
    for (dk = n / 2; dk >= 1; dk = dk / 2)
    {
        for (i = dk + 1; i <= n; i++)
            if (A[i] < A[i - dk])
            {
                A[0] = A[i];
                for (j = i - dk; j > 0 && A[j] > A[0]; j -= dk)
                {
                    A[j + dk] = A[j];
                }
                A[j + dk] = A[0]; // 插入
            }
    }
}

希尔排序,时间复杂度约为O(n1.3),最坏情况O(n2),空间复杂度O(1),不稳定的排序。

交换排序

冒泡排序

冒泡排序,从后往前(或从前往后)两两比较相邻元素的值,若为逆序,则交换,重复n-1趟。

void BubbleSort(int A[], int n)
{
    for (int i = 0; i < n - 1; i++)
    {
        bool flag = false;
        for (int j = n - 1; j > i; j--)
        {
            if (A[j] < A[j - 1])
            {
                swap(A[j], A[j - 1]);
                flag = true;
            }
        }
        if (!flag)
            return;
    }
}

冒泡排序,空间复杂度O(1),时间复杂度O(n2),稳定的排序方法

快速排序

快速排序的基本思想是基于分治法的,任取一个元素pivot作为枢轴,划分为两部分。左半部分<pivot,右半部分>pivot。快速排序的partition有很多种实现方法,这里采用王道408中描述的方法进行实现。

int Partition(int A[], int low, int high)
{
    int pivot = A[low];
    while (low < high)
    {
        while (low < high && A[high] >= pivot) 
            high--;
        A[low] = A[high]; //将比枢轴小的元素移到左端
        while (low < high && A[low] <= pivot) 
            low++;
        A[high] = A[low]; //将比枢轴大的元素移到右端
    }
    A[low] = pivot;
    return low;
}
void QuickSort(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);
    }
}

快速排序:空间复杂度O(logn),时间复杂度O(nlogn),不稳定的排序方法,快速排序是所有内部排序算法中平均性能最优的排序算法

选择排序

简单选择排序

简单选择排序,每一趟选择关键字最小的元素,作为有序子序列的第i个元素。

void SelectSort(int A[], int n)
{
    for (int i = 0; i < n - 1; i++)
    {
        int min = i;
        for (int j = i + 1; j < n; j++)
        {
            if (A[min] > A[j])
            {
                min = j;
            }
        }
        if (min != i)
            swap(A[min], A[i]);
    }
}

选择排序,时间复杂度O(n2),空间复杂度O(1),不稳定的排序算法

堆排序

  1. 构造大根堆;
  2. 交换顶端与末尾元素,此时末尾为最大值,剩余待排序元素为n-1;
  3. 将剩余的n-1个数再次构成大根堆。
#include <iostream>
using namespace std;

// https://www.acwing.com/solution/content/29416/

const int N = 100010;
int h[N], mysize;
int n, m;

void down(int u) 
{
    int t = u;
    if (2 * u <= mysize && h[t] > h[2 * u]) // 子节点小,和最小值交换
        t = 2 * u;
    if (2 * u + 1 <= mysize && h[t] > h[2 * u + 1])
        t = 2 * u + 1;
    if (t != u)
    {
        swap(h[t], h[u]);   
        down(t); // 继续向下调整
    }
}

int main()
{
    cin >> n >> m;
    mysize = n;
    for (int i = 1; i <= n; i++)
        cin >> h[i];
    
    for (int i = n / 2; i > 0; i--) // 从 n/2开始down,建立堆
        down(i); // 每插入一个元素,就down
    // for (int i = 1; i <= n; i++)
    //     cout << h[i] << " ";
    // cout << endl;
    while (m--) // 输出前m小的元素
    {
        cout << h[1] << " "; // 输出堆顶,最小值
        h[1] = h[mysize--]; // 删除堆顶
        down(1); // 让覆盖好的数向下走
    }
    cout << endl;
    return 0;
}

堆排序,空间复杂度O(1),时间复杂度O(nlogn),不稳定的排序算法

归并排序

归并排序,将两个或两个以上的有序表组合成一个新的有序表,将前后相邻的两个有序表归并为一个有序表,两两进行归并。

void Merge(int A[], int left, int mid, int right)
{
    int B[1001];
    for (int i = left; i <= right; i++)
    {
        B[i] = A[i]; //将A中所有元素复制到B,辅助数组
    } 
    int s1 = left, s2 = mid + 1, s = left; //s是指向当前位置的指针
    while (s1 <= mid && s2 <= right)
    {
        if (B[s1] <= B[s2]) A[s++] = B[s1++];
        else if (B[s1] > B[s2]) A[s++] = B[s2++];
    }
    while (s1 <= mid)
    {
        A[s++] = B[s1++]; // 若第一个表未检测完,复制
    }
    while (s2 <= right)
    {
        A[s++] = B[s2++]; // 若第二个表未检测完,复制
    }
}
void MergeSort(int A[], int left, int right)
{
    if (left < right)
    {
        int mid = (left + right) / 2;
        MergeSort(A, left, mid);
        MergeSort(A, mid + 1, right);
        Merge(A, left, mid, right);
    }
}

归并排序,空间复杂度O(n),时间复杂度O(nlogn),稳定的排序算法

基数排序

参考链接

内部排序方法的比较

请添加图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值