在分而治之思想指导下的归并排序和快速排序算法

1.引入
对于数据结构来说最先上手的一定是排序算法了,这时最基础的当然也很重要,从最基础的四种复杂度为O(n2)的排序算法(如果忘记了请移步)到比较烧脑的基数排序当然还有基数排序的前奏箱子排序如果遗忘请移步当然在某些情况下箱子排序和基数排序能够达到惊人的复杂度O(n)但是这并不普适,只适用于特定的情况。那么有没有一些普适的排序算法并且复杂度降到O(n2)以下呢。有的人想到了堆排序,不错堆排序确实可以将复杂度降到O(nlogn)如果遗忘请移步可是这种排序算法要依赖对这种数据结构有没有可以直接堆数组进行排序的呢?今天就来介绍基于分而治之思想的归并排序和快速排序。
2.归并排序:
最坏,平均和最好的情况下,复杂度均可到达O(nlogn)
1)思想:不直接对整个数据排序而是将数据分为几部分,将几部分排好序后在归并到一起。进而如果将数据分为一个一个的数据,然后两个合并成一个依次合并,最终合并成一个有序的归并序列。
2)图解:
在这里插入图片描述
3)C++代码实现:
在merge中是将start-(end1-1)和end1-end2的两个数据归并到一起。

//进行具体的归并
void merge(int x[],int y[],int start,int end1,int end2){
    int first = start;
    int second = end1+1;
    int result = start;

    //归并
    while ((first<=end1)&&(second<=end2)){
        if (x[first] <= x[second]){
            y[result++] = x[first++];//确保稳定性
        } else{
            y[result++] = x[second++];
        }
    }
    //谁溢出了
    if (first>end1){
        for (int i = second; i <= end2; ++i) {
            y[result++] = x[i];
        }
    } else{
        for (int i = first; i <= end1; ++i) {
            y[result++] = x[i];
        }
    }
}

在merge Pass中是确定要将那两个数据集合归并在一起:

void mergePass(int x[],int y[],int n,int segmentSize){
    int i = 0;//归并的起点

    //还可以归并
    while (i<=n-2*segmentSize){
        merge(x,y,i,i+segmentSize-1,i+2*segmentSize-1);
        i+=(2*segmentSize);
    }

    //是奇数个数最后一次将最后一个归并到有序集中
    if (i+segmentSize<n){
        merge(x,y,i,i+segmentSize-1,n-1);
    } else{
        for (int j = i; j < n; ++j) {
            y[j] = x[j];
        }
    }
}

在mergeSort中创建数组b,将a逐步归并到b再将a归并到b最终生成有序的归并集合。

void mergeSort(int a[],int n){
    int *b = new int[n];
    int segmentSize = 1;//初始化的数据段的长度就是一

    while (segmentSize<n){
        mergePass(a,b,n,segmentSize);
        segmentSize+=segmentSize;
        mergePass(b,a,n,segmentSize);
        segmentSize+=segmentSize;
    }

    delete []b;

}

3.快速排序
最坏情况下复杂度为O(n2)最好和平均情况均可到达O(nlogn)
1)思想:就是创建一个支点m将小于m的全部放在m的左边,将大于m的全部放在m的右边,递归下去直至长度小于等于1.
2)图解:
在这里插入图片描述
右边的指针找不大于第一个数据的数据
在这里插入图片描述
在这里插入图片描述
左边的指针找不小于第一个的数据
如果找到数据并且左边指针在右边指针的左侧,则交换数据。
在这里插入图片描述
在这里插入图片描述
当左边指针不再右边指针的左侧时,停止寻找,将第一个数据与左侧最后一个数据交换位置。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
好了接下来就是递归了。
3)C++代码实现:

//寻找最大值
int indexOfMax(int  a[],int n) {

    if(n>0){
        int indexOfMax = 0;


        for(int i=0;i<n;i++){
            if(a[indexOfMax]<a[i]){
                indexOfMax = i;
            } else{

            }
        }
        return indexOfMax;
    } else{
        throw ;
    }
}

void quickSort(int a[],int n){
    if(n<=1) return;

    int max = indexOfMax(a,n);

//    cout<<max;
    int temp = a[max];
    a[max] = a[n-1];
    a[n-1] = temp;

    quickSort(a,0,n-2);
}
void quickSort(int a[],int leftStart,int rightEnd){
    if(leftStart>=rightEnd) return;
    int leftCursor = leftStart;
    int rightCursor = rightEnd+1;//从右边开始的游标要加一否则会少比较一个元素
    int pivot = a[leftStart];//支点或分割元素

    while (true){

        //如果不将最大的元素放在首位这一步可能导致溢出
        //左侧找不小于的
        do{
            leftCursor++;
        }while (a[leftCursor] < pivot);//while中是不符合寻找要求的

        //右侧找不大于的
        do{
            rightCursor--;
        }while(a[rightCursor] > pivot);

        if(leftCursor>=rightCursor) break;

        int temp = a[leftCursor];
        a[leftCursor] = a[rightCursor];
        a[rightCursor] = temp;

    }

    //将小于支点集合的最后一个元素与指点交换位置
    a[leftStart] = a[rightCursor];
    a[rightCursor] = pivot;

    quickSort(a,leftStart,rightCursor-1);//对小于支点的集合进行递归排序
    quickSort(a,rightCursor+1,rightEnd);//对大于支点的集合进行递归排序

}

quickSort(int a[],int n)方法是为了防止第一个dowhile循环溢出,所以将最大的值提前放到最后面去。
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值