超级详细十大排序算法 (c++代码)

2020-04-27  本文已影响0人  洛丽塔的云裳

尊重原创, 以下原理均来自以下链接 :
https://blog.csdn.net/weixin_41190227/article/details/86600821
https://www.cnblogs.com/itsharehome/p/11058010.html
https://blog.csdn.net/qq_39207948/article/details/80006224
注:以下c++代码有任务错误,烦请指正~

0. 术语

稳定 :如果a原本在b前面,而a=b,排序之后a仍然在b的前面;
不稳定 :如果a原本在b的前面,而a=b,排序之后a可能会出现在b的后面;
内排序 :所有排序操作都在内存中完成;
外排序 :由于数据太大,因此把数据放在磁盘中,而排序通过磁盘和内存的数据传输才能进行;
时间复杂度 : 一个算法执行所耗费的时间。
空间复杂度 :运行完一个程序所需内存的大小。

1. 各种排序算法的算法复杂度

n: 数据规模
k: “桶”的个数
In-place: 占用常数内存,不占用额外内存
Out-place: 占用额外内存

2. 各种排序算法

2.1 冒泡排序

冒泡排序 是一种简单的排序算法。 通过交换使相邻的两个数变成小数在前大数在后,这样每次遍历后,最大的数就“沉”到最后面了

算法思想

算法实现

void swap(int& a, int& b) {
    if (a > b) {
        int tmp = a;
        a = b;
        b = tmp;
    }
}
void bubbleSort(vector<int>& nums) {
    for (int i=0; i<nums.size(); i++){
        for (int j=0; j<nums.size()-1-i; j++) {
            if (nums[j] > nums[j+1]) {
                swap(nums[j], nums[j+1]);
            }
        }
    }
}

算法分析

2.2 选择排序

选择排序是表现最稳定的排序算法之一 ,因为无论什么数据进去都是O(n2)的时间复杂度 ,所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间了吧。理论上讲,选择排序可能也是平时排序一般人想到的最多的排序方法了吧。
选择排序(Selection-sort)是一种简单直观的排序算法。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

算法思想

n个记录的直接选择排序可经过n-1趟直接选择排序得到有序结果。具体算法描述如下:

算法实现

void descendingSwap(int& a, int& b) {
    if (a < b) {
        int tmp = a;
        a = b;
        b = tmp;
    }
}
void selectSort(vector<int>& nums) {
   int minIndex;
   for (int i=0; i<nums.size(); i++) {
       minIndex = i;
       for (int j=i+1; j<nums.size();j++){
           if (nums[j] < nums[minIndex]) {
               minIndex = j;
           }
       }
       descendingSwap(nums[minIndex], nums[i]);
   }
}

算法分析

2.3 插入排序

插入排序(Insertion-Sort) 的算法描述是一种简单直观的排序算法。我们在玩打牌的时候,你是怎么整理那些牌的呢?一种简单的方法就是一张一张的来,将每一张牌插入到其他已经有序的牌中的适当位置。当我们给无序数组做排序的时候,为了要插入元素,我们需要腾出空间,将其余所有元素在插入之前都向右移动一位,这种算法我们称之为插入排序

算法思想

算法实现

void insertSort(vector<int>& nums) {
   int curr;
   for (int i=0; i<nums.size(); i++) {
       curr = nums[i];
       int j = i-1, orderIndex = i;
       while (j>=0 && nums[j] >= curr) {
           nums[orderIndex--] = nums[j--];
       }
       nums[orderIndex] = curr;
   }
}

算法分析

2.4 希尔排序

希尔排序是希尔(Donald Shell) 于1959年提出的一种排序算法, 是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序, 同时该算法是冲破O(n^2)的第一批算法之一。无论是插入排序还是冒泡排序,如果数组的最大值刚好是在第一位,要将它挪到正确的位置就需要 n - 1 次移动。也就是说,原数组的一个元素如果距离它正确的位置很远的话,则需要与相邻元素交换很多次才能到达正确的位置,这样是相对比较花时间了。

算法思想

希尔排序的基本步骤,选择增量gap=length/2,缩小增量继续以gap = gap/2的方式,这种增量选择我们可以用一个序列来表示,{n/2,(n/2)/2…1},称为增量序列。希尔排序的增量序列的选择与证明是个数学难题,我们选择的这个增量序列是比较常用的,也是希尔建议的增量,称为希尔增量,但其实这个增量序列不是最优的。此处我们做示例使用希尔增量。
先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,具体算法描述:

算法实现

本质就是每次以gap间距进行插入排序。

void shellSort(vector<int>& nums) {
    int gap, length = nums.size();
    gap = length/2;
    while (gap) {
       int curr;
       for (int i=0; i<nums.size(); i=i+gap) {
            curr = nums[i];
            int j = i - gap, orderIndex = i;
            while (j>=0 && nums[j] >= curr) {
                nums[orderIndex] = nums[j];
                orderIndex -= gap;
                j -= gap;
            }
            nums[orderIndex] = curr;
       }
       gap = gap/2;
    }
}

算法分析

2.5 归并排序

归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。归并排序是一种稳定的排序方法,将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。

算法思想

算法实现

算法分析

2.6 快速排序

算法思想

算法实现

算法分析

2.7 堆排序

算法思想

算法实现

算法分析

2.8 计数排序

算法思想

算法实现

算法分析

2.9 桶排序

算法思想

算法实现

算法分析

2.10 基数排序

算法思想

算法实现

算法分析

上一篇 下一篇

猜你喜欢

热点阅读