【数据结构】快速排序与堆排序

本文详细介绍了快速排序和堆排序两种经典排序算法。对于快速排序,讲解了其基本思想、时间复杂度,并给出了具体实现,包括如何进行Partition操作。而对于堆排序,解释了大根堆的定义,展示了将数组转换为最大堆的过程,以及如何通过交换堆顶元素维持堆性质。代码示例辅助理解这两种排序算法的运作机制。
摘要由CSDN通过智能技术生成

Problem A 快速排序

7-1 快速排序

全屏浏览题目切换布局

作者 朱允刚

单位 吉林大学

给定包含n个元素的整型数组a[1],a[2],…,a[n],利用快速排序算法对其进行递增排序,请输出排序过程,即每次Partition之后的数组。每次选择所处理的子数组的第一个元素作为基准元素。

输入格式:

输入为两行,第一行为一个整数n(1<n≤1000),表示数组长度。第二行为n个空格间隔的整数,表示待排序的数组。

输出格式:

输出为若干行,每行依次输出Partition后的数组,每个元素后一个空格。

输入样例:

5
4 5 3 2 1

输出样例:

2 1 3 4 5 
1 2 3 4 5 
1 2 3 4 5 

思路

快速排序算法通过定义基准Pivot,实现了小元素左移、大元素右移,保证了一定程度的递增有序,同时又对左边和右边的子表分别进行一次快速排序,最终实现全局的递增有序。

快速排序的时间复杂度为O(nlogn),不稳定。

根据教材的代码,本题输出样例的第一行结果我是怎么推也推不出来呀。后来去参考借鉴了一下别人的代码,发现原来在Partition划分部分需要直接用Swap函数来交换元素,最后才模拟出了2 1 3 4 5的结果…总的来说这题的测试样例和对应算法还有待商榷,下面附教材的Partition代码。

int Partition(SqList &S, int low, int high) {
    int pivot = low;
    while (low < high) {
        while (low < high && S.elem[high] > S.elem[pivot])
            --high;
        S.elem[low] = S.elem[high];
        while (low < high && S.elem[low] <= S.elem[pivot])
            ++low;
        S.elem[high] = S.elem[low];
    }
    S.elem[low] = S.elem[pivot];
    return low;
} 

代码

#include <bits/stdc++.h>
using namespace std;

typedef struct SqList {
    int *elem;
    int length;
} SqList;

/// @brief 交换a和b的值
/// @param a 
/// @param b 
void swap(int &a, int &b) {
    int temp = a;
    a = b;
    b = temp;
} // swap

/// @brief 打印顺序表
/// @param S 
void PrintSqList(SqList S) {
    for (int i = 1; i <= S.length; i++) {
        cout << S.elem[i] << " ";
    }
    cout << endl;
} // PrintSqList

/// @brief 构建顺序表,根据需要的大小来分配空间
/// @param S 
void CreateSqList(SqList &S) {
    cin >> S.length;
    S.elem = (int *)malloc((S.length + 1) * sizeof(int));
    for (int i = 1; i <= S.length; i++) {
        cin >> S.elem[i];
    }
} // CreateSqList

/// @brief 划分操作,以low所指元素为基准pivot,大于pivot的元素都在右边,否则都在左边
/// @param S 
/// @param low 
/// @param high 
/// @return 
int Partition(SqList &S, int low, int high) {
    int pivot = low;
    // S.elem[0]=S.elem[low];
    while (low < high) {
        while (low < high && S.elem[high] > S.elem[pivot])
            --high;
        while (low < high && S.elem[low] <= S.elem[pivot])
            ++low;
        swap(S.elem[low], S.elem[high]);
    }
    swap(S.elem[low], S.elem[pivot]);
    return low;
} // Partition

/// @brief 快速排序
/// @param S 
/// @param low 
/// @param high 
void QSort(SqList &S, int low, int high) {
    if (low < high) {
        int pivot = Partition(S, low, high);
        PrintSqList(S);
        QSort(S, low, pivot - 1);
        QSort(S, pivot + 1, high);
    }
} // QSort

/// @brief 快速排序
/// @param S 
void QuickSort(SqList &S) {
    QSort(S, 1, S.length);
    PrintSqList(S);
} // QuickSort

int main() {
    SqList S;
    CreateSqList(S);
    QuickSort(S);
    return 0;
}

Problem B 堆排序

7-2 堆排序

全屏浏览题目切换布局

作者 严华云

单位 湖州师范学院

对n个数,要求用堆排序(最大堆)对其进行排序。

输入格式:

第一行一个n(n<1000)。第二行给出n个数。

输出格式:

输出n行,每行n个数。第一行表示将n个数(将n个数看成一棵树)变成最大堆后的结果,第二行表示将上次结果的根节点交换到现有节点的最后一个节点(然后将除最后一个节点的数看成一颗树),然后将该剩余节点树从新变成最大堆后的结果输出(包括交换到最后的节点),依次类推。

输入样例:

6
7 1 6 4 3 5

输出样例:

7 4 6 1 3 5 
6 4 5 1 3 7 
5 4 3 1 6 7 
4 1 3 5 6 7 
3 1 4 5 6 7 
1 3 4 5 6 7 

思路

要使用堆排序,首先要了解堆的定义。堆分为大根堆和小根堆。在教材里,大根堆的定义就是a[k]>a[2k]&&a[k]>a[2k+1],即双亲大于左右孩子。大根堆排序中每次会将堆中最小的元素上移至根节点,再将其与堆的最后一个元素进行交换,从而得到递增的有序序列。

堆排序的时间复杂度为O(nlogn),不稳定。

代码

#include <bits/stdc++.h>
using namespace std;

typedef struct SqList {
    int *elem;
    int length;
} SqList;

typedef SqList HeapType;

/// @brief 创建堆
/// @param H 
void CreateHeap(HeapType &H) {
    cin >> H.length;
    H.elem = (int *)malloc((H.length + 1) * sizeof(int));
    for (int i = 1; i <= H.length; i++) {
        cin >> H.elem[i];
    }
} // CreateHeap

/// @brief 打印堆,实际上是打印顺序表的元素
/// @param H 
void PrintHeap(HeapType H){
    for (int i = 1; i <= H.length; ++i){
        cout << H.elem[i] << " ";
    }
    cout << endl;
} // PrintHeap

/// @brief 调整堆,使其符合堆的定义要求。堆的定义:a[k]>a[2*k] && a[k]>a[2*k+1]
/// @param H 
/// @param k 
/// @param len 
void HeapAdjust(HeapType &H, int k, int len){
    H.elem[0] = H.elem[k];
    for (int i = 2 * k; i <= len; i *= 2) {
        if (i < len && H.elem[i] < H.elem[i + 1]) {
            i++;
        }
        if (H.elem[0] > H.elem[i]) {
            break;
        } else {
            H.elem[k] = H.elem[i];
            k=i;
        }
    }
    H.elem[k] = H.elem[0];
} // HeapAdjust

/// @brief 堆排序
/// @param H 
void HeapSort(HeapType &H){
    for (int i = H.length / 2;i > 0; --i) {
        HeapAdjust(H, i, H.length);
    }
    PrintHeap(H);
    for (int i = H.length; i > 1; --i) {
        swap(H.elem[1], H.elem[i]);
        HeapAdjust(H, 1, i-1);
        PrintHeap(H);
    }
} // HeapSort

int main() {
    HeapType H;
    CreateHeap(H);
    HeapSort(H);
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值