美文网首页
(C++实现)经典排序算法

(C++实现)经典排序算法

作者: JLGao的简书 | 来源:发表于2019-11-19 16:56 被阅读0次

1. 交换排序

根据数组中两个元素值的大小来交换两个元素在数组中的位置。

1.1 冒泡排序

1.1.1 基本思想: 假设待排序的长度是n,从后往前(或者是从前往后)依次比较相邻的两个元素的大小,
如果是逆序,则交换,直到比较完成。下面是从小到大的排序过程:
(1) 取未排序序列的最后一个元素(待排序的元素);
(2) 在未排序的元素序列中从后向前扫描,如果待排序的元素比新元素小,就交换它们两个;
(3) 重复步骤(2),直到待排序的元素插入与排序的位置;
(4) 重复步骤(1)~(3),知道排序完成。
1.1.2 代码实现:

void bubbleSort(vector<int> &arr, int len){
    for(int i=0; i < len-1; i++){   // n-1趟排序
        int flag = 0;     // 交换的标记
        for(int j=len-1; j>i; j--){
            if(arr[j] < arr[j-1]){
                int temp = arr[j];
                arr[j] = arr[j-1];
                arr[j-1] = temp;
                flag = 1;
            }
        }
        if(flag == 0)   //第一次排序为发生交换,则原序列有序
            return;
    }
}

1.2.3 性能分析:
(1) 空间复杂度:O(1)
(2) 时间复杂度:最好情况下(待排序的序列为有序序列,比较n-1次,交换0次),为O(n)。最坏情况下(待排序序列为逆序序列,比较\sum_{i=1}^{n-1} {(n-i)} = \frac{n(n-1)}{2}次,交换\sum_{i=1}^{n-1} {3(n-i)} = \frac{3n(n-1)}{2}次):O(n^2)
(3) 稳定性:当相等的两个元素进行比较时,不会发生交换,两个元素在排序前和排序后的相对位置不会发生交换。因此,针对以上所写冒泡排序算法,是稳定的。

1.2 快速排序

1.2.1 基本思想: 基于分治法。在待排序表L[1,...,n]中任取一个元素pivot为基准,通过一趟排序将序列划分为两部分:L[1,...,k-1]和L[k+1,...,n],使得L[1,...,k-1]的所有元素值都小于pivot,L[k+1,...,n]的所有元素值都大于pivot,而pivot在序列最终的L[k]位置上。随后,分别递归的对两个子序列重复以上过程,直到序列内只有一个元素或者为空。由此可知,每一趟的快速排序都有一个元素在序列的最终位置上。
1.2.2 代码实现:

int partition(vector<int> &arr, int low, int high){
    int pivot = arr[low];
    while(low < high){
        while(low<high && arr[high] >= pivot)
            --high;
        if(low<high)
            arr[low++] = arr[high];
        
        while(low<high && arr[low]<=pivot)
            ++low;
        if(low < high)
            arr[high--] = arr[low];
    }
    arr[low] = pivot;
    return low;
}

void quickSort(vector<int> &arr, int low, int high){
    if(low < high){
        int pivotPos = partition(arr, low, high);
        quickSort(arr, low, pivotPos - 1);
        quickSort(arr, pivotPos + 1, high);
    }
}

1.2.3 性能分析:
(1) 空间复杂度:快速排序需要递归栈保存每次递归调用时所需要的信息,为O(log_2{n})。(可借助二叉树的思想)
(2) 时间复杂度:快速排序的时间复杂度与划分是否对称有关。最好的情况下,每次划分后的序列是对称的,时间复杂度为O(n^2);最坏的情况下,初始序列是有序或是逆序,时间复杂度为O(nlog_2{n})
(3) 稳定性:举例,初始序列为{2,2,3},快速排序后为{2,2,3}。值相同的两个元素在序列中的相对位置发生了变化。

2. 插入排序

插入排序:每次将一个待插入的元素插入到已经排序好的子序列中,直到全部的序列插入完成。

2.1 直接插入排序

2.1.1 基本思想:
假设L是一个由n个元素的待排序序列,现将L(i)插入到有序列L[1,2,...,i-1]中,则排序过程如下:
(1) 查找L(i)在L[1,2,...,i-1]中待插入的位置k;
(2) 将L[k,...,i-1]中的所有元素往后移动一个位置;
(3) 将L(i)复制到L(k)中;
(4) 重复步骤(1)-(3),直到所有的元素排序完成。
2.1.2 代码实现:

void insertSort(vector<int> &arr, int len){
    for(int i = 1; i < len; i++){
        int current = arr[i];
        int j = i - 1;
        while(j >= 0 && current < arr[j]){
            arr[j + 1] = arr[j];
            --j;
        }
        arr[j + 1] = current;
    }
}

2.1.3 性能分析:
(1) 空间复杂度: 借助了常数个存储单元,空间复杂度为O(1)
(2) 时间复杂度: 直接插入排序的时间复杂度与待排序序列的初始状态有关。最好情况下,待排序序列有序,每个元素需要比较1次,时间复杂度为O(n);最坏的情况下,待排序序列逆序,总的比较次数为\sum_{i=2}^{n} {i}=\frac{n(n-1)-1}{2},总的移动次数为\sum_{i=2}^{n} {i+1}=\frac{n(n-1)-2}{2}.因此,时间复杂度为O(n^2)
(3) 稳定性:待插入的元素再有序序列中查找待插入的位置时,遇到相同元素即停止,不会发生交换。因此,直接插入排序是稳定的。

2.2 折半插入排序

2.2.1 基本思想:
假设L是一个由n个元素的待排序序列,现将L(i)插入到有序列L[1,2,...,i-1]中,则排序过程如下:
(1) 折半查找L(i)在L[1,2,...,i-1]中待插入的位置k;
(2) 将L[k,...,i-1]中的所有元素往后移动一个位置;
(3) 将L(i)复制到L(k)中;
(4) 重复步骤(1)-(3),直到所有的元素排序完成。
2.2.2 代码实现:

void binaryInsertSort(vector<int> &arr, int len){
    int left, right, mid, temp;
    for(int i = 1; i < len; i++){
        temp = arr[i];   //待插入元素
        left = 0;
        right = i - 1;
        while(left <= right){
            mid = (left + right) / 2;
            if(temp < arr[mid])
                right = mid - 1;
            else
                left = mid + 1;
        }
        for(int j = i - 1; j > right; j--)
            arr[j + 1] = arr[j];
        arr[right + 1] = temp;
    }
}

2.2.3 性能分析:
(1) 空间复杂度:O(1)
(2) 时间复杂度:O(n^2)。第i趟折半查找待插入元素的在已排序序列中位置的时间复杂度为O(log_2{i}),则总的比较次数为O(nlog_2{n});总的移动次数为O(n^2)。所以折半插入排序的时间复杂度为O(n^2)
(3) 稳定性:折半插入排序是稳定的。

主函数代码:

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

int main(){
    int len;
    cin >> len;
    vector<int> arr(len);    
    cout << "待排序序列为:";
    for(int i = 0; i < len; i ++){
        cin >> arr[i];
    }
    // bubbleSort(arr, len);
    // quickSort(arr, 0, len - 1);
    // insertSort(arr, len);
    // binaryInsertSort(arr, len);    
    cout << "排序结果为:";
    for(int i = 0; i < len; i ++){
        cout << arr[i] << ' ';
    }
    cout << endl;
    return 0;
}

相关文章

  • 排序算法详细代码实现

    算法分类 算法时间复杂度 选择排序 插入排序 C++实现 Python实现 冒泡排序 Python实现 归并排序 ...

  • 七大排序算法之快速排序

    七大排序算法之快速排序 @(算法笔记)[排序算法, 快速排序, C++实现] [TOC] 快速排序的介绍: 快速排...

  • 七大排序算法之冒泡排序

    七大排序算法之冒泡排序 @(算法笔记)[排序算法, 冒泡排序, C++实现] 冒泡排序介绍 冒泡排序是七大排序算法...

  • 排序算法

    十大经典排序算法Lua版八大排序算法C++/C#

  • 一文搞定十大经典排序算法(Java实现)

    本文总结十大经典排序算法及变形,并提供Java实现。参考文章:十大经典排序算法总结(Java语言实现)快速排序算法...

  • (C++实现)经典排序算法

    1. 交换排序 根据数组中两个元素值的大小来交换两个元素在数组中的位置。 1.1 冒泡排序 1.1.1 基本思想:...

  • python 排序算法

    文章概述 介绍各大常用经典的排序算法和效率,以及python实现常用算法(冒泡排序,选择排序,快速排序,插入排序)...

  • 关于不同排序算法的性能比较

    一个排序算法性能测试的c++实现,用于测试不同排序算法的耗时,代码如下: 比较直接排序与选择排序示例: 测试结果:

  • 2018-06-30

    排序算法之归并排序 归并排序算法是排序算法中的经典算法之一,其核心思想是利用归并的思想实现的排序方法,该算法采用经...

  • 排序算法

    小胡子哥:聊一聊排序算法白话经典算法系列之五 归并排序的实现

网友评论

      本文标题:(C++实现)经典排序算法

      本文链接:https://www.haomeiwen.com/subject/dahyictx.html