数据结构——快速排序与归并排序

本文详细介绍了两种经典的排序算法——快速排序和归并排序。快速排序采用分治策略,通过选取枢轴元素将数组划分为两部分,再递归排序。归并排序则通过不断合并已排序的子序列来达到整体有序。两者都是O(nlogn)的时间复杂度,但快速排序在平均情况下更优,而归并排序则是稳定的排序算法。文中提供了C++实现代码示例,并分析了它们各自的特点和适用场景。

快速排序

定义:
快速排序是由冒泡排序改进而得的。在冒泡排序过程中,只对相邻的两个记录进行比较,因此每次交换两个相邻记录时只能消除一个逆序。如果能通过两个不相邻记录的一次交换,消除多个逆序,则会大大加快排序的速度。快速排序方法中的一次交换能消除多个逆序。

具体步骤:
1.选择待排序表中的第一个记录作为枢轴,附设两个指针low和high,初始时分别指向标的下界和上界;
2.从标的最右侧位置一次向左搜索,找到第一个关键字小于枢轴关键字的记录,将其移至low处;
3.然后再从表的最左侧位置,依次向右搜索找到第一个关键字大于枢轴的记录,将其移至high处;
4.重复2和3,直至low和high相等为止;
(实际上相当于取出第一个记录,从high向左搜索找到一个值放入第一个记录,再从low向右搜索找到一个值放入上轮空缺的high值。)

算法特点:
(1)记录非顺次的移动导致排序方法是不稳定的。
(2)排序过程中需要定位表的下界和上界,所以适合用于顺序结构,很难用于链式结构。
(3)当n较大时,在平均情况下快速排序是所有内部排序方法中速度最快的一种,所以其适合初始记录无序,n较大的情况。

时间复杂度空间复杂度
O(nlogn)O(1)

代码:(以对vector排序为例)

#include <iostream>
#include <vector>
using namespace std;
//快速排序
int Partition(vector<int> &arr, int low, int high)//low high指针移动一趟
{
    int p = arr[low];
    while (low < high) {
        while (low < high && arr[high] >= p)    high--;
        arr[low] = arr[high];
        while (low < high && arr[low] <= p)     low++;
        arr[high] = arr[low];
    }
    arr[low] = p;
    return low;//返回枢轴位置
}
void QSort(vector<int> &arr, int low, int high)//递归
{
    if (low < high) {
        int p = Partition(arr, low, high);
        QSort(arr, low, p - 1);
        QSort(arr, p + 1, high);
    }
}
int main()
{
    vector<int> test = { 49,38,65,97,76,13,27,49 };
    QSort(test, 0, test.size()-1);
    //输出排序后的向量
    for (int k = 0; k < test.size(); k++)
        cout << test[k] << " ";
}

归并排序

定义:
归并排序就是将两个或两个以上的有序表合并成一个有序表的过程,将两个有序表合并成一个有序表的过程称为2-路归并,2-路归并最简单和常用。

具体步骤:
2-路归并排序将R[low,high]中的记录归并排序后放入T[low,high]中,当序列长度等于1时,递归结束。否则:
1.将当前序列一分为二,求出分裂点mid=(low+high)/2;
2.对子序列R[low,mid]递归,进行归并排序,结果放入S[low,high]中;
3.对子序列R[mid+1,high]递归,进行归并排序,结果放入S[mid+1,high]中;
4.调用算法Merge,将有序的两个子序列S[low,mid]和S[mid+1,high]归并为一个有序的序列T[low,high];

算法特点:
(1)归并排序为稳定排序
(2)可用于链式结构,且不需要附加存储空间,但递归实现时仍需要开辟相应的递归工作栈。

时间复杂度空间复杂度
O(nlogn)O(n)

代码:(以对vector排序为例)

#include <iostream>
#include <vector>
using namespace std;
//归并排序
//将R[low,mid] R[mid+1,high]归并为有序表T[low,high]
void Merge(vector<int> &R, vector<int> &T, int low, int mid, int high)
{   
    int i = low, j = mid + 1, k = low;
    while (i <= mid && j <= high) {
        if (R[i] < R[j])
            T[k++] = R[i++];
        else
            T[k++] = R[j++];
    }
    while (i <= mid) T[k++] = R[i++];
    while (j <= high) T[k++] = R[j++];
}
//R归并排序后放入T中
void MSort(vector<int> &R, vector<int> &T, int low, int high)
{
    if (low == high) T[low] = R[low];
    else {
        int mid = (low + high) / 2;
        vector<int> S(R.size());
        MSort(R, S, low, mid);
        MSort(R, S, mid+1, high);
        Merge(S, T, low, mid, high);
    }
}
int main()
{
    vector<int> test = { 49,38,65,97,76,13,27,49 };
    MSort(test, test, 0, test.size()-1);
    for (int k = 0; k < test.size(); k++)
        cout << test[k] << " ";
}

实验结果截图:
在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值