基础数据结构和算法——8、高级排序算法

1.归并排序

在这里插入图片描述

1.1 步骤

实现两个有序数组的合并

void merge(int arr[],int n,int mid);

拆分并合并数组

void merge_sort(int arr[],int n);

1.2 参考代码

void merge(int arr[],int n,int mid){
    int temp[n];
    memcpy(temp,arr,n*sizeof(int));
    int p = 0,q = mid,k = 0;
    while(p<mid && q<n) arr[k++] = temp[p]<temp[q]?temp[p++]:temp[q++];
    if(p<mid) memcpy(arr+k,temp+p,(mid-p)*sizeof(int));
    if(q<n) memcpy(arr+k,temp+q,(n-q)*sizeof(int));
}
void merge_sort(int arr[],int n){
    if(n <= 1) return;
    int mid = n/2;
    merge_sort(arr,mid);
    merge_sort(arr+mid,n-mid);
    merge(arr,n,mid);
}
// [0,mid)  [mid,n)
void merge(int* arr,int n,int mid){
    int temp[n];
    int p =0, // 前半部分下标
    q=mid,   // 后半部分下标
    k=0;  // 结果下标
    while(p<mid && q<n){
        if(arr[p]<arr[q]){
            temp[k] = arr[p];
            p++;
        }else{
            temp[k] = arr[q];
            q++;
        }
        k++;
    }
    while(p<mid) temp[k++] = arr[p++];
    while(q<n) temp[k++] = arr[q++];
    memcpy(arr,temp,n*sizeof(int));
}

void merge_sort(int* arr,int n){
    if(n<=1) return;
    int mid = n/2;
    merge_sort(arr,mid);
    merge_sort(arr+mid,n-mid);
    merge(arr,n,mid);
}

1.3 时间复杂度

一共拆分log2n次,每次比较n个元素,一共比较nlog2n次。

1.4 空间复杂度

随着n的增长,排序需要增加额外空间n+log2n(临时数组n和递归调用函数栈log2n),空间复杂度为O(n)。

2. 快速排序

  • 左游标是i哨兵,右游标是j哨兵。
    在这里插入图片描述
  • 第一次交换
    在这里插入图片描述
  • 第二次交换
    在这里插入图片描述
  • 基准交换
    在这里插入图片描述
    在这里插入图片描述

2.1 步骤

  1. 根据基准元素重排数组
int partition(int arr[],int n);
  1. 依次排列两个部分
void quick_sort(int arr[],int n);

2.2 参考代码

int partition(int arr[],int n){
    int key = arr[0];
    int p = 0,q = n-1;
    while(p<q){
        while(p<q && arr[q]>=key) q--;
        arr[p] = arr[q];
        while(p<q && arr[p]<=key) p++;
        arr[q] = arr[p];
    }
    arr[p] = key;
    return p;
}
void quick_sort(int arr[],int n){
    if(n<=1) return;
    int pivot = partition(arr,n);
    quick_sort(arr,pivot);
    quick_sort(arr+pivot+1,n-pivot-1);
}
// 快速排序
int partition(int* arr,int n){  // 基准点排序
    int priot = arr[0];  // 设置第一个元素为基准
    int i=0,j=n-1;
    while(i<j){
        while(i<j && arr[j]>=priot) --j;
        while(i<j && arr[i]<=priot) ++i;
        if(i<j){
            swap(arr[i],arr[j]);
        }
    }
    swap(arr[0],arr[i]);
    return i;
}
void quick_sort(int* arr,int n){
    if(n<=1) return;
    int pos = partition(arr,n);  // 基准点
    quick_sort(arr,pos);  //  基准点左边
    quick_sort(arr+pos+1,n-(pos+1));   // 基准点右边
}

2.3 时间复杂度

一共拆分log2n次,每次比较n个元素,一共比nlog2n较次。

2.4 空间复杂度

随着n的增长,排序需要增加额外空间log2n(递归函数栈空间),空间复杂度为O(log2n)。

2.5 优化

交换指针法

int partition(int arr[],int n){
    int key = arr[0];
    int p = 0,q = n-1;
    while(p<q){
        while(p<q && arr[q]>=key) q--;
        while(p<q && arr[p]<=key) p++;
        if(p>=q) break;
        swap(arr+q,arr+p);
    }
    swap(arr,arr+q);
    return q;
}

3. 希尔排序

3.1 原理

  1. 给定一个长度n的列表,选择一定的步长gap,将列表分成若干个子列表sublist
    例如:长度n=9步长gap=3分成3个子列表sublist

在这里插入图片描述
2. 对每一个子列表sublist进行插入排序。
在这里插入图片描述
3. 依次减小步长gap,重复上述操作。直到gap为1。

希尔排序比插入排序的优势:
通过分组排序使元素逐渐靠近最终位置,从而减少了插入排序 时的移动次数。(先粗调再微调)

3.2 步骤

在这里插入图片描述

  1. 划分间距gap并执行排序
void shell_sort(int arr[],int n);
  1. 根据间距gap执行插入排序
void insertion_sort(int arr[],int n,int gap);
  1. 根据间距gap插入
void insert(int arr[],int n,int gap);

3.3 参考代码

void insert(int arr[],int n,int gap){
    for(int i=n-1-gap;i>=0;i-=gap){
        if(arr[i+gap]<arr[i]){
            swap(arr+i+gap,arr+i);
        }else{
            break;
        }
    }
}
void insertion_sort(int arr[],int n,int gap){
    for(int i=gap;i<=n;++i){
        insert(arr,i,gap);
    }
}
void shell_sort(int arr[],int n){
    int gap = n;
    do{
        gap = gap/2;
        insertion_sort(arr,n,gap);
    }while(gap>1);
}

比较:插入排序与希尔排序

在这里插入图片描述

3.5 优化

移动代替交换

void insert(int arr[],int n,int gap){   
    int key=arr[n-1];
    int i=0;
    for(i=n-1;i>=gap&&arr[i-gap]>key;i-=gap){
        arr[i] = arr[i-gap];
    }
    arr[i] = key;
}

void insertion_sort(int arr[],int n,int gap){
    for(int i=gap;i<n;++i){// 插入元素i操作
        insert(arr,i+1,gap);
    }
}

void shell_sort(int arr[],int n){
    for(int i=n/2;i>0;i/=2){// gap序列
        insertion_sort(arr,n,i);
    }
}

在这里插入图片描述

4. 小结

在这里插入图片描述

5. 算法选择标准

如何选择排序算法?(定性)
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值