微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

数据结构九大排序方法总结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),稳定的排序算法

基数排序

咕咕咕

内部排序方法的比较

请添加图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐