七种常见的排序算法C++实现

冒泡排序、选择排序、直接插入排序、希尔排序、 归并排序、快速排序、堆排序
在这里插入图片描述

#include<string>
#include<vector>
#include<iostream>
using namespace std;

vector<int> maopaos(vector<int> &nums);  /// 冒泡排序
vector<int> selects(vector<int> &nums);  /// 选择排序
vector<int> inserts(vector<int> &nums);  /// 插入排序
vector<int> shells(vector<int> &nums);  /// 希尔排序
vector<int> guibins(vector<int> &nums);  /// 归并排序
vector<int> quicks(vector<int> &nums);  /// 快速排序
vector<int> heaps(vector<int> &nums);  /// 堆排序

void printr(const string &name,const vector<int> &r) {
    cout<< name <<" result: ";
    for(auto &n : r) {
        cout<<n <<",";
    }
    cout<<endl;
}

int main() {
    {
        vector<int> nums = {4, 2, 3, 6, 5};
        auto res = maopaos(nums);
        printr("maopao", res);
    }

    {
        vector<int> nums = {4, 2, 3, 6, 5};
        auto res = selects(nums);
        printr("select", res);
    }

    {
        vector<int> nums = {4, 2, 3, 6, 5};
        auto res = inserts(nums);
        printr("inserts", res);
    }

    {
        vector<int> nums = {4, 2, 3, 6, 5};
        auto res = shells(nums);
        printr("shells", res);
    }
    {
        vector<int> nums = {4, 2, 3, 6, 5};
        auto res = guibins(nums);
        printr("guibins", res);
    }
    {
        vector<int> nums = {4, 2, 3, 6, 5};
        auto res = quicks(nums);
        printr("quicks", res);
    }

    {
        vector<int> nums = {4, 2, 3, 6, 5};
        auto res = heaps(nums);
        printr("heaps", res);
    }

    return 0;
}
//*************************************************
/// 冒泡:比较相邻两个元素,如果第一个比第二个大,就交换(升序)
vector<int> maopaos(vector<int> &nums) {  /// 冒泡排序
    int n = nums.size();
    if(n<2) return nums;
    bool flag = true;
    for(int i = 0; i < n; ++i) {
        for(int j = 0; j < n-i-1; ++j) {
            if(nums[j]>nums[j+1]) {
                int tmp = nums[j+1];
                nums[j+1] = nums[j];
                nums[j]  = tmp;
                flag = false;
            }
        }
        if(flag) break;
    }
    return nums;
}
//*************************************************
/// 选择排序:每次都从未排序部分中选择最小的元素放到未排序部分的最前面
vector<int> selects(vector<int> &nums) {  /// 选择排序
    int n = nums.size();
    if(n<2) return nums;
    for (int i = 0; i<n; ++i) {
        int min_index = i;
        for(int j = i+1; j < n; ++j) {
            if(nums[j]<nums[min_index]) min_index = j;
        }
        if(min_index != i) {
            int tmp = nums[min_index];
            nums[min_index] = nums[i];
            nums[i]  = tmp;
        }
    }
    return nums;
}
//*************************************************
///插入排序: 将当前访问的元素的前面部分当成是已经排好的序列,然后把当前元素插入到前面序列的合适位置
vector<int> inserts(vector<int> &nums) {  /// 插入排序
    int n = nums.size();
    if(n<2) return nums;
    for (int i = 1; i<n; ++i) {
        int tmp = nums[i];
        int j = i;
        while(j>0 && nums[j-1]>tmp) {
            nums[j] = nums[j-1];
            j--;
        }
        if(j!=i) {
            nums[j]=tmp;
        }
    }
    return nums;
}
//*************************************************
/// 希尔排序:直接插入排序的优化,缩小增量排序。
vector<int> shells(vector<int> &nums) {  /// 希尔排序
    int n = nums.size();
    if(n<2) return nums;
    int gap = n/2;
    while(gap > 0) {
        for(int i = 0; i<n-gap; i++) {
            int tmp = nums[i+gap];
            if (tmp < nums[i]) {
                nums[i+gap] = nums[i];
                nums[i] = tmp;
            }
        }
        gap = gap/2 ;
    }

    return nums;
}
//*************************************************
/// 归并排序:先将数组不断二分,知道各个子数组只包含一个元素,然后将各个子数组两两合并,
///           合并后的序列是排序好的序列。然后再两两合并...知道恢复原本数组长度。
vector<int> merge(vector<int> left, vector<int> right) {
    /// 合并两个升序数组,合并后的数组也是升序的!!!!!!!
    int n1 = left.size(), n2 = right.size();
    vector<int> ans(n1+n2);
    int k1 = 0, k2 = 0, i = 0;
    while(k1 < n1 && k2 < n2) {
        if(left[k1] <= right[k2]) ans[i++] = left[k1++];
        else ans[i++] = right[k2++];
    }
    while(k1 < n1)  ans[i++] = left[k1++];
    while(k2 < n2)  ans[i++] = right[k2++];
    return ans;
}
vector<int> guibins(vector<int> &nums) {  /// 归并排序
    int n = nums.size();
    if(n<2) return nums; /// 递归结束条件
    vector<int> left(nums.begin(), nums.begin() + n/2);
    vector<int> right(nums.begin() + n/2, nums.end());
    return merge(guibins(left), guibins(right));   // 递归!!
}

//*************************************************
/// 从数列中挑出一个元素,称为 “基准”(pivot);
/// 重新排序数列,所有元素比基准值小的摆放在基准前面,
/// 所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。
/// 在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
/// 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序;

int partion(vector<int> &nums, int l, int r) {  // 选基准值,并且排序
    int pivot = l;
    int index = pivot + 1;
    for(int i = index; i <= r; ++i) {
        if(nums[i] < nums[pivot]) {
            /// 交换下标 i 和 index的值
            swap(nums[i], nums[index]);
            /// index加1,使得index下标总是指向一个大于基准数的值。
            index++;
        }
    }
    /// 交换基准值 和 大于他的序列的第一个值,交换后,基准值前面都是小于他的,后面都是大于他的。
    swap(nums[pivot], nums[index-1]);
    return index-1;
}

void quicksort(vector<int>& nums, int l, int r) {
    if(l<r) {
       int index = partion(nums, l, r);
       quicksort(nums, l, index-1);
       quicksort(nums, index+1, r);
    }
}

vector<int> quicks(vector<int> &nums) {  /// 快速排序
    int n = nums.size();
    if(n<2) return nums;
    quicksort(nums, 0, n-1);
    return nums;
}

//*************************************************
/// 升序排列
/// 堆排序,先建大顶堆,然后不断的把堆顶取走,再把堆尾放到堆顶,然后更新大顶堆。每次取走了都是剩余元素中最大的。
/// 注意 :数组实现二叉树,下标 k 的左子树节点下标为 2*k+1, 右子树节点下标 2*k+2。
/// 注意:                  下标 i 的父节点下标为 (i-1)/2
/// 注意:                   如果数组长度为 n , 那么下标大于 n/2 的节点都是 叶子节点。

/// nums的下标 0~heapsize-1 部分构成二叉树数组,对于树节点 k, 将 以k在以他为父节点的树中不断下沉。
void sink(vector<int> &nums, int heapsize, int k) {
    int maxone = k;   // 从此节点及其左右子节点中挑出最大值作为此节点。
    int left = 2*k+1;
    int right = 2*k+2;
    if (left < heapsize) maxone = nums[maxone]<nums[left] ? left : maxone;
    if (right < heapsize) maxone = nums[maxone]<nums[right] ? right : maxone; /// 注意决不能此处写成 right 跟 k 比。
    if (maxone != k) {
        std::swap(nums[k], nums[maxone]);
        sink(nums, heapsize, maxone); // 继续下沉
    }
}

/// 删除堆顶,并将其置于数组中二叉树序列的下一个元素。
void deletetop(vector<int> &nums, int &heapsize) {
    std::swap(nums[0], nums[heapsize-1]);
    heapsize--;
    sink(nums, heapsize, 0); // 保证堆顶是二叉树中最大的元素
}

void buildheap(vector<int> &nums, int heapsize) {
    int i = (heapsize-1)/2;
    while(i>=0) {
        sink(nums, heapsize, i);
        i--;
    }
}

vector<int> heaps(vector<int> &nums) {  /// 堆排序
    int n = nums.size();
    if(n<2) return nums;
    buildheap(nums, n);
    int heapsize = n;        /// 注意不能直接用n,因为以下 deletetop 会改变n 的值。
    for(int i = 0; i < n-1; ++i) deletetop(nums, heapsize);
    return nums;
}
//*************************************************
  • 参考:
    1. https://mp.weixin.qq.com/s?__biz=MzUyNjQxNjYyMg==&mid=2247484184&idx=1&sn=62965b401aa42107b3c17d1d8ea17454&chksm=fa0e6c99cd79e58f298e9026f677f912bd8c8e55edb48fc509b2b5834f05e529a9b47d59d202&scene=21#wechat_redirect
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值