C++实现常用八大排序算法

前言

自己总结的C++八大排序算法,编码规范全部按照公司要求。欢迎补充,后续逐步完善。

算法复杂度比较

在这里插入图片描述

交换排序

冒泡排序

代码思路:它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。每趟将最大值放置在末尾。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

/*
相邻元素比较:选择小的元素放在前面
*/
void bubble_sort(vector<int> &nums, int n)
{
    bool flag;
    for(int i = 0; i < n - 1; i++)
    {
        flag = false;
        for(int j = 0; j < n - i - 1; j++)
        {
            if(nums[j] > nums[j+1])
            {
                swap(nums[j], nums[j+1]);
                flag = true;
            }
        }
        
        if(!flag)
        {
            break;
        }
    }
}

快速排序

代码思路:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。

/*
选择一个基准,将基准移动到数据中间,使得左边的数据都小于基准,右边的数都大于基准
递归划分,当数据元素等于1个的就是一个的时候就是有序的了
*/
void quick_sort(vector<int> &nums, int l, int r){
    if(l + 1 >=r)
    {
        return;
    }

    int low = l;
    int high = r -1;
    int key = nums[low];
    while (low < high)
    {
        while (low < high && nums[high] >= key)
        {
            high--;
        }
        nums[low] = nums[high];

        while (low < high && nums[low] <= key)
        {
            low++;
        }
        nums[high] = nums[low];
    }
    
    nums[low] = key;
    quick_sort(nums, l, low);
    quick_sort(nums, low+1, r);
}

插入排序

简单插入排序

代码思路:通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

/*
插入排序法:
拿着当前位置元素和前面的元素进行比较,只要当前元素比前面的元素大,则插入到该元素前面
直到前面的元素不满足要求,记录插入位置。
先拿出来 再比较插入
*/
void insert_sort(vector<int> &nums, int n)
{
    for(int i = 0; i < n; i++)
    {
        for(int j = i; j>0 && nums[j]<nums[j-1]; j--)
        {
            swap(nums[j], nums[j-1]);
        }
    }
}

希尔排序

代码思路: 先将整个记录, 通过间隔分成若干个子序列, 分别进行插入排序, 待整个序列基本有序时, 再进行一次插入排序.
因为插入排序时, 有可能重复移动数据, 希尔排序, 是一次移动较多的距离(间隔),减少重复移动, 所以降低了时间复杂度.
时间复杂度约为: O(n^(3/2)).

//核心思想还是使用插入排序算法
//通过分组,让数据在小规模内有序,减小递归增量使得整体有序
void shell_sort(vector<int> &nums)
{
    int i = 0;
    int j = 0;
    int temp = 0;
    int size = nums.size();
    int gap = size/2;//设置增量
    while(gap >= 1)
    {
        for(i = gap; i<size; i++) //对所有组采用直接插入排序
        {
            temp = nums[i];//temp保存gap的数字
            j = i - gap;
            while ((j >= 0) && (temp < nums[j]))
            {
                nums[j + gap] = nums[j];
                j -= gap;
            }
            nums[j + gap] = temp;
        }
        gap /=2;
    }
}

选择排序

简单选择排序

代码思路:选择前面n-1个数中的最大值,和当前队尾数据交换,因为要交换最大值,所以要记录最大值位置的索引。
首先在未排序序列中找到最大元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最大元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

/*
从该位置后面选择最小的元素放在该位置
*/
void select_sort(vector<int > &nums, int n)
{
    for(int i = 0; i<n-1; i++)
    {
        int min = i;
        for(int j = i+1; j<n; j++)
        {
            if(nums[j]<nums[mid])
            {
                min = j;
            }
        }

        swap(nums[min], mums[i]);
    }
}

堆排序

代码思路:堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

/*
先建立一个堆,在依据堆顶为最大值的性质,循环抽出堆顶最大值交换到堆的末尾位置,有序序列,由于抽出最大值破坏了堆的性质,因此要重新heapify
而在建立堆的过程中,首先面临的是一堆无序的数,需要从最后一个节点的父节点开始heapify,才能使得整个数组变成堆,其中heapify的过程就是递归将调整父节点子节点的过程
*/

void creat_heap(vector<int> &nums, int i, int num) //创建大堆顶,i为当节点,n为堆的大小,如果儿子节点比父亲节点大,则进行交换。
{
    for(; i >= 0; --i)
    {
        int left = 2*i+1; //左子树节点
        int right = 2*i+2; //右子树节点
        int max = 0;
        if(left < num && nums[left]>nums[max])
        {
            max = left;
        }
        if(right < num && nums[right]>nums[max])
        {
            max = right;
        }
        //交换子节点与父节点
        if(nums[max] > nums[i])
        {
            swap(nums[max], nums[i]);
        }
        
    }
}

void heap_sort(vector<int> &nums)
{
    int size = nums.size();
    creat_heap(nums, size/2 - 1, size);
    for(int j = size - 1; j>=0; j--)//交换第一个元素和最后一个元素后,堆的大小减1
    {
        swap(nums[0], nums[j]);

        int i = j/2-1;
        creat_heap(nums, i, j);
    }
}

归并排序

代码思路:归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。

/*
把长度为n的输入序列分成两个长度为n/2的子序列;
对这两个子序列分别采用归并排序;
将两个排序好的子序列合并成一个最终的排序序列。
*/
void merge(vector<int> &nums, int l, int mid, int r)
{
    int *temp = new int(r - l + 1);
    int p1 = l;
    int p2 = mid + 1;
    int i = 0;
    while (p1 <= mid && p2 <=r)
    {
        temp[i++] = nums[p1]>nums[p2] ? nums[p2++] : nums[p1++]; 
    }

    while (p1<=mid)
    {
        temp[i++]=nums[p1++];
    }

    while (p2<=r)
    {
        temp[i++]=nums[p2++];
    }

    for(int i=0; i<r; i++)
    {
        nums[i++] = temp[i++];
    }
}

void merge_sort(vector<int> &nums, int l, int r)
{
    if(l < r)
    {
        int mid = (r+l)/2;
        merge_sort(nums, l, mid);
        merge_sort(nums, mid+1, r);
        merge(nums, l, mid, r);
    }
}
  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值