前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Day23-排序-快排&堆排&归并排序

Day23-排序-快排&堆排&归并排序

作者头像
BUPTrenyi
发布2019-07-30 12:13:06
4080
发布2019-07-30 12:13:06
举报
文章被收录于专栏:算法其实很好玩

一 鸽王回来了!

由于前段时间真的有点忙,鸽了大家一个礼拜多

然后,鸽王今天回来了,明天继续更图,今天小试牛刀一下

排序算法很基础,基础还是要打扎实~

像冒泡排序这种时间复杂度为O(N²)的渣渣排序算法就不更了

快排的平均时间复杂度,堆排和归并的时间复杂度都是O(nlog(n))

所以这仨都值得一写,也是面试的高频排序题

二 快排开始搞起来!

Q:实现快速排序

冷静分析一下快排的基本思想:(以最终升序为例)

1.取数组第一个元素,为基准值;

2.建立左右指针,分别指向第一个和最后一个元素;

3.在左指针 < 右指针 下进行循环:

右指针--,直到找到比基准值小的元素,将左右指针指向的元素进行交换;

左指针++,直到找到比基准值大的元素,将左右指针指向的元素进行交换;

4.此时初始数组的第一个元素,即我们刚才定义的基准值,已在其最终位置上,那么对该数左边的部分递归快排,对该数右边的部分递归快排;

代码语言:javascript
复制
//
// Created by renyi on 2019-07-26.
//
#include <iostream>
#include <vector>
using namespace std;

void printArray(vector<int> nums){
    for (int i = 0; i < nums.size(); i++) {
        printf("[%d]", nums[i]);
    }
    printf("\n");
}

void swap(int &a, int &b){
    int temp = a;
    a = b;
    b = temp;
}

void quickSort(vector<int> &nums, int low, int high){
    if (low >= high){
        return;
    }

    int i = low;
    int j = high;
    int base = nums[i];

    while (i < j){
        while (i < j && nums[j] >= base){
            j--;
        }
        swap(nums[i], nums[j]);

        while (i < j && nums[i] <= base){
            i++;
        }
        swap(nums[i], nums[j]);
    }

    quickSort(nums, low, i-1);
    quickSort(nums, i+1, high);
}

int main(){
    int temp[] = {7, 9, 5, 1, 2, 8, 6, 4, 0, 3, 10};
    vector<int> result;
    for (int i = 0; i < 11; i++) {
        result.push_back(temp[i]);
    }
    
    printArray(result);
    quickSort(result, 0, result.size()-1);
    printArray(result);
    
    return 0;
}

三 堆排开始搞起来!

Q:实现堆排序

冷静分析:先知道堆排序要干什么(仍然以最终升序为例)

网上找个图

堆排序的思路就是:这是初始的堆,我们现在要构造一个大顶堆。然后将大顶堆的堆顶,即当前最大的元素和最后一个元素交换,即把最大的堆顶,放到了最后面。同时将堆可操作的长度-1,即后面的堆顶,放到了倒数第二个位置。同时需要实现一个函数,完成每次交换完两个元素之后,调整堆使其继续保持为大顶堆。

这是初始的堆

利用我们自己实现的函数,将初始堆,构造为大顶堆

这是最终构造好的大顶堆

然后开始堆排序,将堆顶80与最后一个元素40进行交换,此时80就在其最终位置上了,可操作长度-1。接下来利用我们自己实现的函数,调整堆,使其继续为大顶堆,那么此时大顶堆的堆顶一定是70,将堆顶70交换到了下标为7的位置,依次类推~

代码语言:javascript
复制
//
// Created by renyi on 2019-07-26.
//
#include <iostream>
#include <vector>
using namespace std;

void printArray(vector<int> nums){
    for (int i = 0; i < nums.size(); i++) {
        printf("[%d]", nums[i]);
    }
    printf("\n");
}

void swap(int &a, int &b){
    int temp = a;
    a = b;
    b = temp;
}

void adjustHeap(vector<int>& nums, int parNode, int high){
    int newParNode = parNode;
    int j = 2 * parNode + 1;//取根节点的左孩子

    while (j <= high){//如果j=high,说明没有右孩子,high就是左孩子
        if (j < high && nums[j] <= nums[j+1]){
            j += 1;//一个根节点下如果有两个孩子,将j指向更大的那个孩子
        }

        if (nums[j] >= nums[newParNode]){//如果j指向的孩子大于父节点,就交换
            swap(nums[j], nums[newParNode]);
            newParNode = j;
            j = j * 2 + 1;
        } else{
            break;
        }
    }
}

void heapSort(vector<int>& nums){
    int last = nums.size() - 1;
    int lastParNode = nums.size() / 2 - 1;//最后一个父节点

    while (lastParNode >= 0){
        adjustHeap(nums, lastParNode, last);
        lastParNode -= 1;//建立最大堆,是从后往前调整,每调整好一个节点,就从后往前移动一个节点
    }

    //上面的while循环结束之后,即建立起了一个最大堆
    //接下来开始堆排序,精髓就是,交换头和尾,把最大的放最后面,再调整为最大堆,继续交换
    while (last > 0){
        swap(nums[0], nums[last]);
        adjustHeap(nums, 0, last-1);//从前往后调整最大堆
        last -= 1;
    }
}

int main(){
    int temp[] = {7, 9, 5, 1, 2, 8, 6, 4, 0, 3, 10};
    vector<int> result;
    for (int i = 0; i < 11; i++) {
        result.push_back(temp[i]);
    }

    printArray(result);
    heapSort(result);
    printArray(result);
    return 0;
}

四 归并排序搞起来!

Q:实现归并排序

冷静分析:

归并排序也很经典,我就不画图了,大概讲一下思路:

归并排序的精髓:将大问题不断递归拆分为小问题,直到不能拆分为止,对最终拆分的一个个小部分进行排序&合并,然后一步一步向上回溯,最后一次是将两个有序数组合并为了一个有序数组,整体是递归&回溯的思想~

至于代码实现,就是讲原始数组,按下标一半进行拆分,然后将左边的数组递归拆分,将右边的数组递归拆分,直到不能拆分;此时进行回溯,即合并两个有序数组,一步一步向上回溯,最终合并两个大的有序数组~

个人认为归并排序的算法思路最精妙,也是本人最喜欢的排序算法

代码语言:javascript
复制
//
// Created by renyi on 2019-07-26.
//
#include <iostream>
#include <vector>
using namespace std;

void printArray(vector<int> nums){
    for (int i = 0; i < nums.size(); i++) {
        printf("[%d]", nums[i]);
    }
    printf("\n");
}

void mergeTwoSortedVector(vector<int>& vec1, vector<int>& vec2, vector<int>& vec){
    int i = 0;//遍历vec1的下标
    int j = 0;//遍历vec2的下标

    while (i < vec1.size() && j < vec2.size()){
        if (vec1[i] <= vec2[j]){
            vec.push_back(vec1[i]);
            i++;
        } else{
            vec.push_back(vec2[j]);
            j++;
        }
    }

    for (; i < vec1.size(); i++) {//谁更长,直接把剩余部分追加进去vec
        vec.push_back(vec1[i]);
    }
    for (; j < vec2.size(); j++) {
        vec.push_back(vec2[j]);
    }
}

void mergeSort(vector<int>& vec){
    if (vec.size() < 2){
        return;
    }

    int mid = vec.size() / 2;
    vector<int> vec1;
    vector<int> vec2;

    for (int i = 0; i < mid; i++) {
        vec1.push_back(vec[i]);
    }
    for (int j = mid; j < vec.size(); j++) {
        vec2.push_back(vec[j]);
    }

    mergeSort(vec1);
    mergeSort(vec2);
    vec.clear();
    mergeTwoSortedVector(vec1, vec2, vec);
}

int main(){
    int temp[] = {7, 9, 5, 1, 2, 8, 6, 4, 0, 3, 10};
    vector<int> result;
    for (int i = 0; i < 11; i++) {
        result.push_back(temp[i]);
    }
    
    printArray(result);
    mergeSort(result);
    printArray(result);

    return 0;
}

这三份代码的运行结果皆一致,均为

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-07-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 算法其实很好玩 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档