排序算法总结一

排序在算法中是比较基础也是相当重要的一部分,在这里将会把各种排序算法那加以总结,并实现;

排序算法分类

  • 比较排序
    • 冒泡排序 (稳定,时间 O(n2) ,空间 O(1)
    • 选择排序 (稳定,时间 O(n2) ,空间 O(1)
    • 插入排序 (稳定,时间 O(n2) ,空间 O(1)
    • shell排序 (不稳定,时间 O(n1.3) ,空间 O(1)
    • 归并排序 (稳定,时间 O(nlogn) ,空间 O(n)
    • 快速排序 (稳定,时间 O(nlogn)
  • 桶排序 (稳定,时间 O(nlogn)
  • 计数排序 (稳定,时间 O(kn)
  • 基数排序
  • 堆排序 (稳定,时间 O(nlogn)

    注解:一般说快速排序是不稳定的, 但事实上快速排序有稳定的实现方法,故在这里认为快排也是稳定的

排序算法实现

接下来会按照以下思路去分析每种排序算法:

  • 给出每种算法的实现思路;
  • 提供算法实现的C++源码;
  • 代码逻辑和值得注意的细节;

大家也可以到这个网站上找对应排序的可视化理解各种排序算法的逻辑;

冒泡排序

思路

相邻两个元素进行比较然后交换;

  • 在第一轮中将最大的元素交换到数组的最后面;
  • 第二轮中将第二大的元素交换到数组的倒数第二个位置;
  • 重复上面的步骤,直至所有的元素都变换到对应的位置;

C++源码实现

在实现中,是以函数模板的形势实现的;利用vector存储数组;为了方便打印每个循环中nums中的状态,调用了algorithm库里面的for_each函数;为了直接使用本文中的代码,需要包含的头文件有

#include <vector>
#include <algorithm>
#include <iostream>

其他的排序算法也是如此,后面就不在重述;

template <typename T>
void bubbleSort(vector<T> &nums){
    for(size_t i = 0; i < nums.size(); i++) {
        //打印出每次循环后当前的nums里面的元素
        for_each(nums.begin(),nums.end(),[](const int num){ cout << num << " ";} );
        cout << endl;
        for(size_t j = 1; j + i < nums.size(); j++)
            if(nums[j-1] > nums[j]) // keep stable
                swap(nums[j-1],nums[j]);
    }
}

第5行代码主要是为了方便打印每次循环后,数组里面的元素变化的状态,真正实现的时候,可以删掉这一行代码;第8行中,要注意符号,这个将会与排序算法是否稳定有一定关系

测试代码和冒泡排序结果

为了测试冒泡排序,主函数代码如下:

int main()
{
    vector<int> nums = {8, 10, 5, 7, 11, 9, 6, 2};
    bubbleSort(nums);
    for_each(nums.begin(),nums.end(),[](const int num){ cout << num << " ";} );
    return 0;
}

当测试其他排序算法的时候,只需要修改第3行调用排序算法的修改或者修改nums数组里面额数据即可;

测试结果:

8 10 5 7 11 9 6 2
8 5 7 10 9 6 2 11
5 7 8 9 6 2 10 11
5 7 8 6 2 9 10 11
5 7 6 2 8 9 10 11
5 6 2 7 8 9 10 11
5 2 6 7 8 9 10 11
2 5 6 7 8 9 10 11
2 5 6 7 8 9 10 11

选择排序

思路

每次选择最大(小)的元素放在数组的最后面(最前面)

  1. 找出A[1..n]中最小的元素,与A1交换;
  2. 找出A[2..n]中最小的元素 ,与A2交换;
  3. 重复以上的步骤,直到排序完成;

C++源码实现

template <typename T>
void selectionSort(vector<T> &nums) {
    int index;
    for(size_t i = 0; i < nums.size(); i++){
        index = i;
        for(size_t j = i; j < nums.size(); j++) {
            if(nums[j] < nums[index]) index = j;
        }
        swap(nums[i],nums[index]);
    }
}

插入排序

思路

像打扑克牌一样,将每一张牌按照大小插入到相应的位置

  1. 已经排好序的序列 a0,a1,ai1 ,逆序查找 ai 的合适位置 j
  2. j位置及其后的元素依次后移,将 ai 插入到位置j,组成新的排好序的序列 a0,a1...ai
  3. 重复1、2步骤,直到排好所有的元素

上述后面两个步骤可以整合到一起,寻找合适位置的时候,同时完成元素的移动;

C++源码实现

template <typename T>
void insertionSort(vector<T> &nums) {
    for(size_t i = 1; i < nums.size(); i++) {
        T key = nums[i];
        int j = i - 1;
        while(j >= 0 && key < nums[j]) {
            nums[j+1] = nums[j];
            j--;
        }
        nums[j+1] = key;
    }
}

代码第6行while循环就是在寻找元素key对应的位置,如果位置不对,就把元素后移一位(第7行),j递减之后继续循环,直到找到对应的位置,此时将key放在对应的位置;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值