归并排序和快速排序

前言

之前文章提到过的希尔排序它有划时代的意义,打破了一个认知——排序算法的复杂度不可能超过O(n*n),之后各种各样更高效的排序算法就开始出现了,比如这次文章中提到的归并排序和快速排序

归并排序

基本思想:
两个或者两个以上的有序序列合并成一个新的有序序列,有序序列V[0]…V[m]和V[m+1]…V[n-1]合并成V[0]…V[n-1],这种归并方法称为2路归并,以此类推,将多个有序序列归并为一个新的有序序列,称为多路归并,特别注意的是,要归并的序列必须是有序的,如下图所示,归并排序其实是一个递归调用的过程,不断等分成2路压栈,到最后无路可分则合并出栈最后形成一个有序序列,递归出口为只有一个元素时,如80
在这里插入图片描述
归并排序的代码实现
可以看到无序序列被分成两有序部分,所以我们得开辟另一个数组来存放有序序列,首先8比16小,把8放在开辟数组的第一个元素,接着16比21小,把16放在开辟数组的第二个元素,然后21比37小,把21放在开辟数组的第三个元素…反复的进行,最后就在开辟的数组形成有序序列,最后将开辟的数组赋值到原来的无序数组
在这里插入图片描述
代码演示

  template <typename T>
static void Merge(T src[],T helper[],int begin,int mid,int end,bool min2max = true)
 {
     int i=begin;
     int j=mid+1;
     int k=begin;
     /*将数据有序等存放到新数组helper*/
     while((i<=mid)&&(j<=end))
     {
         if(min2max?src[i]<src[j]:src[i]>src[j])
         {
             helper[k++] = src[i++];
         }
         else
         {
             helper[k++] = src[j++];
         }
     }
     /*若B部分先结束,则拷贝剩下的A部分到helper数组中*/
     while(i<=mid)
     {
         helper[k++] = src[i++];
     }
     /*若A部分先结束,则拷贝剩下的B部分到helper数组中*/
     while(j<=end)
     {
        helper[k++] = src[j++];
     }
     /*将helper数组拷贝到原来的数组*/
     for(i=begin;i<=end;i++)
     {
         src[i] = helper[i];
     }
 }
 /*合并函数*/
 template <typename T>
 static void Merge(T src[],T helper[],int begin,int end,bool min2max = true)
 {
     if(begin == end)
     {
        return ;
     }
     else
     {
         int mid = (begin+end)/2;
         Merge(src,helper,begin,mid,min2max);//先递归2分,如图1的1-4的左边部分
         Merge(src,helper,mid+1,end,min2max);//先递归2分,如图1的1-4的右边部分
         Merge(src,helper,begin,mid,end,min2max);//合并最后的有序序列,如上图合并A,B部分
     }
 }
 /*合并函数*/
 template <typename T>
 static void Merge(T array[],int len,bool min2max = true)
 {
     T* helper = new T[len];//申请有序序列数组
     if(helper != NULL)
     {
         Merge(array,helper,0,len-1,min2max);//调用合并函数
     }
     else
     {
         delete []helper;
     }
}

结果:
在这里插入图片描述
在这里插入图片描述

快速排序

基本思想
任取序列中的某个元素作为基准将整个序列划分为左右两个子序列,左侧子序列中所有元素都小于或等于j基准元素,右侧子序列中所有元素都大于基准元素,基准元素排在两个子序列中间,分别对这两个子序列重复进行划分,直到所有的数据元素都排在相应位置上为止,如下图所示,快速排序其实也是递归调用
在这里插入图片描述
下面为动画演示过程,首先我们选取21作为基准元素(pivot),比21小的元素放到21左边,比21大的元素放在21右边,此时就是基准就位了,继续左右两边的元素做快速排序…不断的递归快速排序直到找到递归出口,就是只剩下一个元素
在这里插入图片描述
代码演示

template <typename T>
/*基准算法*/
static int  Partition(T array[],int begin,int end,bool min2max)
{
    T pv = array[begin];
    while(begin<end)
    {
        while((begin<end)&&(min2max?(array[end]>pv):(array[end]<pv)))
        {
           end--;
        }
        Swap(array[begin],array[end]);
        while((begin<end)&&(min2max?(array[begin]<=pv):(array[begin]>=pv)))
        {
           begin++;
        }
        Swap(array[begin],array[end]);
    }
    array[begin] = pv;
    return begin;
}
/*排序函数,递归函数*/
template <typename T>
static void Quick(T array[],int begin,int end,bool min2max)
{
    if(begin<end)
    {
        int pivot = Partition(array,begin,end,min2max);//调用基准函数划分
        Quick(array,begin,pivot-1,min2max);//快排基准左边
        Quick(array,pivot+1,end,min2max);//快排基准右边
    }
}
template <typename T>
static void Quick(T array[],int len,bool min2max = true)
{
    Quick(array,0,len-1,min2max);
}

结果:
在这里插入图片描述

总结

归并排序需要额外的辅助空间才能完成,其空间复杂度为O(n),归并排序的时间复杂度为O(nlogn),是一种稳定的排序法,快速排序的时间复杂度为O(nlogn),一种不稳定的排序法

归并排序快速排序都是常见的排序算法。归并排序的基本思想是将两个及以上的有序表合并为一张有序表,通过分治法将待排序序列分为若干个有序子序列,然后再逐步合并这些子序列,最终得到一个有序序列。归并排序的时间复杂度为O(nlogn)。而快速排序的基本思想是通过分割和递归的方式将一个序列划分为较小的子序列,然后对这些子序列进行排序,最终得到一个有序序列。快速排序的时间复杂度为O(nlogn)。 在C语言中,可以使用递归的方式来实现归并排序快速排序。下面给出一个简单的代码示例: 归并排序的C语言代码示例: ```c #include <stdio.h> void merge(int arr[], int left, int mid, int right) { int i, j, k; int n1 = mid - left + 1; int n2 = right - mid; int L[n1], R[n2]; for (i = 0; i < n1; i++) L[i] = arr[left + i]; for (j = 0; j < n2; j++) R[j] = arr[mid + 1 + j]; i = 0; j = 0; k = left; while (i < n1 && j < n2) { if (L[i] <= R[j]) { arr[k] = L[i]; i++; } else { arr[k] = R[j]; j++; } k++; } while (i < n1) { arr[k] = L[i]; i++; k++; } while (j < n2) { arr[k] = R[j]; j++; k++; } } void mergeSort(int arr[], int left, int right) { if (left < right) { int mid = left + (right - left) / 2; mergeSort(arr, left, mid); mergeSort(arr, mid + 1, right); merge(arr, left, mid, right); } } int main() { int arr[] = { 12, 11, 13, 5, 6, 7 }; int n = sizeof(arr) / sizeof(arr[0]); mergeSort(arr, 0, n - 1); printf("Sorted array: \n"); for (int i = 0; i < n; i++) printf("%d ", arr[i]); printf("\n"); return 0; } ``` 快速排序的C语言代码示例: ```c #include <stdio.h> void swap(int* a, int* b) { int t = *a; *a = *b; *b = t; } int partition(int arr[], int low, int high) { int pivot = arr[high]; int i = (low - 1); for (int j = low; j <= high - 1; j++) { if (arr[j] < pivot) { i++; swap(&arr[i], &arr[j]); } } swap(&arr[i + 1], &arr[high]); return (i + 1); } void quickSort(int arr[], int low, int high) { if (low < high) { int pi = partition(arr, low, high); quickSort(arr, low, pi - 1); quickSort(arr, pi + 1, high); } } int main() { int arr[] = { 10, 7, 8, 9, 1, 5 }; int n = sizeof(arr) / sizeof(arr[0]); quickSort(arr, 0, n - 1); printf("Sorted array: \n"); for (int i = 0; i < n; i++) printf("%d ", arr[i]); printf("\n"); return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值