七大排序算法——直接插入排序、希尔排序、冒泡排序、快速排序、简单选择排序、堆排序、归并排序

typedef struct
{
    // int r[MAXSIZE + 1]; //用于存储排序数组,r[0]用作哨兵或者临时变量
    vector<int> r{0, 50, 10, 90, 30, 70, 40, 80, 60}; //方便测试,直接定义容器存储数据
    int length = 8;                                   //记录顺序表的长度
} SqList;
void swap(SqList &L, int i, int j)
{ //交换L数组r中下标为i和j的元素
    int temp = L.r[i];
    L.r[i] = L.r[j];
    L.r[j] = temp;
}
vector<int> test{0, 1, 19, 5, 13, 8, 18, 3, 7, 4, 6, 2, 10};
//**********************************基于交换思想的排序:冒泡排序、快速排序**************************
/**
 * @description: 冒泡递增排序,平均时间复杂度是O(n^2,且算法稳定
 * @param  {vector<int>&v}
 * @return {}
 */
void BubbleSort(vector<int> &v)
{
    bool flag = true;
    int temp;
    for (int i = 0; i < v.size() && flag; i++) //需要循环v.size()-1趟
    {
        flag = false; //初始化
        for (int j = 0; j < v.size() - i - 1; j++)
        { //每趟循环v.size()-1-i次
            if (v[j] > v[j + 1])
            { //需要交换
                temp = v[j];
                v[j] = v[j + 1];
                v[j + 1] = temp;
                flag = true; //如果有数据交换,则flag为true
            }
        }
    }
}
/**
 * @description: 快速排序(递增),平均时间复杂度是O(nlog2n),且快速排序是一种不稳定的排序算法,就平均计算时间而言,快速排序是我们所有讨论的内排序方法中最好的一个
 *                由于需要递归调用,因此外封装了一个函数
 * @param  {vector<int>&v}
 * @return {无}
 */
//交换顺序表L中的元素,使枢轴记录到位,并且返回所在位置
int Partition(SqList &L, int low, int high)
{
    L.r[0] = L.r[low];       //将整个顺序表的第一个位置作为哨兵或者临时数据
    int pivotkey = L.r[low]; //用子表的第一个元素作为枢轴元素(即比较的元素)
    while (low < high)
    { //从表的两端交替向中间扫描,当low=high时候元素全部扫描完毕
        while (low < high && L.r[high] >= pivotkey)
            --high;
        L.r[low] = L.r[high];
        while (low < high && L.r[low] <= pivotkey)
            ++low;
        L.r[high] = L.r[low];
    }
    L.r[low] = L.r[0];
    return low; //返回枢轴所在的位置
}
void QuickSort(SqList &L, int low, int high)
{
    int pivot; //定义中间枢轴值
    if (low < high)
    {
        pivot = Partition(L, low, high); //算出枢轴值,根据枢轴值将表分为;两个子表
        QuickSort(L, low, pivot - 1);    //对抵子表进行递归排序
        QuickSort(L, pivot + 1, high);   //对高子表进行递归排序
    }
}
//**********************************基于选择思想的排序:简单选择排序、堆排序**************************
/**
 * @description: 简单选择排序,平均时间复杂度是O(n^2,不稳定排序算法
 * @param  {SqList &L}
 * @return {}
 */
void SelectSort(SqList &L)
{
    int k;
    for (int i = 1; i < L.length; i++)
    { //0号元素为哨兵,故下标从1开始
        k = i;
        for (int j = i + 1; j <= L.length; j++)
        {
            if (L.r[j] < L.r[k])
                k = j; //记录最小值位置
        }
        if (k != i)
        {
            //交换r[i]和r[k]
            L.r[0] = L.r[i];
            L.r[i] = L.r[k];
            L.r[k] = L.r[0];
        }
    }
}
/**
 * @description: 堆排序,平均时间复杂度是O(nlog2n)
 * @param  {SqList &}
 * @return 无}
 */
void HeapAdjust(SqList &L, int s, int m)
{
    int temp;
    temp = L.r[s];
    for (int j = 2 * s; j <= m; j *= 2) //沿着较大的孩子节点向下筛选
    {                                   //根节点为i,则该根节点的左孩子为2i,右孩子为2i+1
        if (j < m && L.r[j] < L.r[j + 1])
            ++j; //j为较大节点的下标
        if (temp >= L.r[j])
            break;
        L.r[s] = L.r[j]; //交换
        s = j;
    }
    L.r[s] = temp;
}
void HeapSort(SqList &L)
{
    //将现有的待排序序列构建成一个大顶堆
    for (int i = L.length / 2; i > 0; i--) //完全二叉树最后一个叶子节点为n,则它的双亲一定是n/2,即最后一个非叶子节点为n/2,故i初始值为L.length / 2
    {
        HeapAdjust(L, i, L.length);
    }
    //逐步将每个最大值的根节点与末尾元素交换,并且再调整成大顶堆
    for (int i = L.length; i > 1; i--)
    {
        swap(L, 1, i); //交换根节点与最后一个元素
        HeapAdjust(L, 1, i - 1);
    }
}
//**********************************基于归并思想的排序:2路归并排序**************************
/**
 * @description: 归并排序,平均时间复杂度是O(nlog2n)
 * @param  {SqList &}
 * @return {}
 */

1、快速排序程序:

   void quickSort(vector<int>&nums,int first,int end){//快读排序
        int left=first;
        int right=end;
        //结束标志
        if(first>=end)return;
        int i = rand() % (right- left + 1) + left; //生成随机数
        swap(nums[i],nums[left]);
        int key=nums[first];//比较的值,随机的那个
        while(first<end){
            //从后往前走
            while(first<end&&nums[end]>=key)//一定要有等于号
                end--;
            nums[first]=nums[end];//将较小的值换到比较值的位置
            //从前往后走
            while(first<end&&nums[first]<=key)
                first++;
            nums[end]=nums[first];//将较大值换到了后面,end位置现在是空闲可以放较大值   
        }
        nums[first]=key;
        quickSort(nums,left,first-1);//前半部分递归
        quickSort(nums,first+1,right);//后半部分递归
    }

2、归并排序

    vector<int> sortArray(vector<int>& nums) {
        int len=nums.size();
        vector<int>tmp(len,0);
        mergeSort(nums,tmp,0,len-1);
        return nums;
    }
    void  mergeSort(vector<int>&nums,vector<int>&tmp,int low,int high){
        if(low>=high)return;
        int mid=(high+low)/2;
        int start1=low,end1=mid;
        int start2=mid+1,end2=high;
        //递归左子数组
        mergeSort(nums,tmp,start1,end1);
        //递归右子数组
        mergeSort(nums,tmp,start2,end2);
        //两两归并子数组
        int index=low;
        
        //分别比较两数组的首元素大小,知道一个数组全部比完
        while(start1<=end1&&start2<=end2){
            tmp[index++]=nums[start1]<nums[start2]?nums[start1++]:nums[start2++];
        }
        
        //若第一个数组没有比完,则直接将该数组后续部分全部拼接到tmp中
        while(start1<=end1){
            tmp[index++]=nums[start1++];
        }
        //若第一个数组没有比完,则直接将该数组后续部分全部拼接到tmp中
        while(start2<=end2){
         tmp[index++]=nums[start2++];
        }
        //比完之后要将排好序的数组填入之前的数组,一边更大的两个有序数组进行比较
        for(int i=low;i<=high;i++){
            nums[i]=tmp[i];
        }

    }

3、堆排序

    //堆排序,top k问题一般都用堆排序,比其他排序算法要快
    //大顶堆:是一个完全二叉树,每个节点的值大于或等于其左右孩子节点的值
    //小顶堆:是一个完全二叉树,每个节点的值小于或者等于左右孩子节点的值
    void heapify_sort(vector<int>&nums,int n){
        //建立大根堆,从树的最后一个非叶子节点开始,
        //对每个结点进行heapify操作,然后向上走
        int tmp=(n-2)/2;//完全二叉树的最后一个非叶子节点为n-2/2,序号从0开始,n为节点个数
        for(int i=tmp;i>=0;i--){
            heapify(nums,n,i);
        }
        //建立大根堆之后,每次交换最后一个结点和根节点
        for(int i=0;i<n;i++){
            swap(nums.front(),nums[n-i-1]);
            heapify(nums,n-i-1,0);//交换之后,节点数量减少1个,并且继续构建大顶堆,交换了顶节点,所以从顶节点开始构建大顶堆
        }
    }
    void heapify(vector<int>&nums,int n,int i){
        int l=2*i+1,r=2*i+2;//l为i的左孩子,r为i的右孩子
        int max=i;
        //若左孩子存在
        if(l<n&&nums[l]>nums[max])max=l;
        //若右孩子存在
        if(r<n&&nums[r]>nums[max])max=r;
        //若最大值不是该节点
        if(max!=i){
            swap(nums[i],nums[max]);
            heapify(nums,n,max);
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值