PTA作业7-1 本程序题请用尽量多的排序算法测试&排序总结

给定N个(长整型范围内的)整数,要求输出从小到大排序后的结果。

本题旨在测试各种不同的排序算法在各种数据情况下的表现。各组测试数据特点如下:

数据1:只有1个元素;
数据2:11个不相同的整数,测试基本正确性;
数据3:103个随机整数;
数据4:104个随机整数;
数据5:105个随机整数;
数据6:105个顺序整数;
数据7:105个逆序整数;
数据8:105个基本有序的整数;
数据9:105个随机正整数,每个数字不超过1000。
输入格式:
输入第一行给出正整数N(≤10
5
),随后一行给出N个(长整型范围内的)整数,其间以空格分隔。

输出格式:
在一行中输出从小到大排序后的结果,数字间以1个空格分隔,行末不得有多余空格。

输入样例:
11
4 981 10 -17 0 -20 29 50 8 43 -5

输出样例:
-20 -17 -5 0 4 8 10 29 43 50 981

冒泡排序

在这里插入图片描述

#include <stdio.h>
#include <malloc.h>
void bubble_sort(int arr[],int n){
    int temp;
    for(int i=1;i<=n-1;i++){
        for(int j=1;j<=n-i;j++){
            if(arr[j]>arr[j+1]){
                temp=arr[j];
                arr[j]=arr[j+1];
                arr[j+1]=temp;   
            }
        }
    }
}

int main(){
    int n;
    scanf("%d",&n);
    int *arr=(int*)malloc(sizeof(int)*n);
    for(int i=1;i<=n;i++){
        scanf("%d",&arr[i]);
    }
    bubble_sort(arr,n);
    printf("%d",arr[1]);
    for(int i=2;i<=n;i++){
        printf(" %d",arr[i]);
    }
}

优化冒泡排序
在这里插入图片描述

#include <stdio.h>
#include <malloc.h>
void bubble_sort(int arr[],int n){
    if(n<2)
        return ;
    int temp;
    for(int i=1;i<=n-1;i++){
        int flag=1;
        for(int j=1;j<=n-i;j++){
            if(arr[j]>arr[j+1]){
                flag=0;
                temp=arr[j];
                arr[j]=arr[j+1];
                arr[j+1]=temp;   
            }
        }
        if(flag)
            break;
    }
}
int main(){
    int n;
    scanf("%d",&n);
    int *arr=(int*)malloc(sizeof(int)*n);
    for(int i=1;i<=n;i++){
        scanf("%d",&arr[i]);
    }
    bubble_sort(arr,n);
    printf("%d",arr[1]);
    for(int i=2;i<=n;i++){
        printf(" %d",arr[i]);
    }
}

再优化冒泡排序
在这里插入图片描述

#include <stdio.h>
#include <malloc.h>

void bubble_sort(int arr[],int n){
    if(n<2)
        return ;
    int lastExchangeIndes=0;    //记录最后一次交换的位置   
    int sortBorder=n;           //无序数列的边界,每次只需要比到边界为止
    for(int i=1;i<n;i++){
        int flag=1;
        for(int j=1;j<sortBorder;j++){
            if(arr[j]>arr[j+1]){
                flag=0;
                int temp=arr[j];
                arr[j]=arr[j+1];
                arr[j+1]=temp;
                lastExchangeIndes=j;
            }
        }
        sortBorder=lastExchangeIndes;
        if(flag)
            break;
    }
}
int main(){
    int n;
    scanf("%d",&n);
    int *arr=(int*)malloc(sizeof(int)*n);
    for(int i=1;i<=n;i++){
        scanf("%d",&arr[i]);
    }
    bubble_sort(arr,n);
    printf("%d",arr[1]);
    for(int i=2;i<=n;i++){
        printf(" %d",arr[i]);
    }
}
快速排序(递归写法)

在这里插入图片描述

#include <stdio.h>
#include <malloc.h>
int Partition(int arr[],int low,int high){
    int pivot=arr[low];
    while(low<high){
        while(low<high&&arr[high]>=pivot) high--;
        arr[low]=arr[high];
        while(low<high&&arr[low]<=pivot) low++;
        arr[high]=arr[low];
    }
    arr[low]=pivot;
    return low;
}
void Quicksort(int arr[],int low,int high){
    int pivoloc;
    if(low<high){
        pivoloc=Partition(arr,low,high);
        Quicksort(arr,low,pivoloc-1);
        Quicksort(arr,pivoloc+1,high);
    }
}

int main(){
    int n;
    scanf("%d",&n);
    int *arr=(int*)malloc(sizeof(int)*n);
    for(int i=1;i<=n;i++){
        scanf("%d",&arr[i]);
    }
    Quicksort(arr,1,n);
    printf("%d",arr[1]);
    for(int i=2;i<=n;i++){
        printf(" %d",arr[i]);
    }
}

快速排序(迭代)

在这里插入图片描述

#include <stdio.h>
#include <malloc.h>
typedef struct Range{
    int start,end;
}Range;
Range new_Range(int start,int end){
    Range r;
    r.start=start;
    r.end=end;
    return r;
}
void QuickSort(int arr[],int n){
    Range r[n];          //r模拟栈
    int p=0;
    r[++p]=new_Range(1,n);
    while(p){
        Range range=r[p--];
        if(range.start>=range.end)
            continue;
        int low=range.start;
        int high=range.end;
        int pivot=arr[low];
        while(low<high){
            while(low<high&&arr[high]>=pivot) high--;
            arr[low]=arr[high];
            while(low<high&&arr[low]<=pivot) low++;
            arr[high]=arr[low];
        }
        arr[low]=pivot;
        r[++p]=new_Range(range.start,low-1);
        r[++p]=new_Range(low+1,range.end);
    }
}
int main(){
    int n;
    scanf("%d",&n);
    int *arr=(int*)malloc(sizeof(int)*n);
    for(int i=1;i<=n;i++){
        scanf("%d",&arr[i]);
    }
    QuickSort(arr,n);
    printf("%d",arr[1]);
    for(int i=2;i<=n;i++){
        printf(" %d",arr[i]);
    }
}

插入排序

直接插入排序

在这里插入图片描述

#include <stdio.h>
#include <malloc.h>
void insertion_sort(int arr[],int n){
    
    for(int i=2;i<=n;i++){
        if(arr[i]<arr[i-1]){
            arr[0]=arr[i];
            int j=i-1;
            for(;arr[0]<arr[j];j--){
                arr[j+1]=arr[j];
            }            
            arr[j+1]=arr[0];
        }
    }
}
int main(){
    int n;
    scanf("%d",&n);
    int *arr=(int*)malloc(sizeof(int)*n);
    for(int i=1;i<=n;i++){
        scanf("%d",&arr[i]);
    }
    insertion_sort(arr,n);
    printf("%d",arr[1]);
    for(int i=2;i<=n;i++){
        printf(" %d",arr[i]);
    }
}

在这里插入图片描述

#include <stdio.h>
#include <malloc.h>
void insertion_sort(int arr[],int n){
    for(int i=2;i<=n;i++){
        arr[0]=arr[i];
        int j=i-1;
        for(;arr[0]<arr[j];j--){
            arr[j+1]=arr[j];
        }            
        arr[j+1]=arr[0];
    }
}
int main(){
    int n;
    scanf("%d",&n);
    int *arr=(int*)malloc(sizeof(int)*n);
    for(int i=1;i<=n;i++){
        scanf("%d",&arr[i]);
    }
    insertion_sort(arr,n);
    printf("%d",arr[1]);
    for(int i=2;i<=n;i++){
        printf(" %d",arr[i]);
    }
}

二分插入排序

在这里插入图片描述

#include <stdio.h>
#include <malloc.h>
void insertion_sort(int arr[],int n){
    int low=0,high=0,mid=0;
    for(int i=2;i<=n;i++){
        arr[0]=arr[i];
        low=1;
        high=i-1;
        while(low<=high){
            mid=(low+high)/2;
            if(arr[0]<arr[mid])
                high=mid-1;
            else low=mid+1;
        }
        int j=i-1;
        for(;j>=high+1;j--){
            arr[j+1]=arr[j];
        }            
        arr[high+1]=arr[0];
    }
}
int main(){
    int n;
    scanf("%d",&n);
    int *arr=(int*)malloc(sizeof(int)*n);
    for(int i=1;i<=n;i++){
        scanf("%d",&arr[i]);
    }
    insertion_sort(arr,n);
    printf("%d",arr[1]);
    for(int i=2;i<=n;i++){
        printf(" %d",arr[i]);
    }
}

二路插入排序
希尔排序

增量序列为{5,3,1}
在这里插入图片描述
增量序列为{9,7,5,3,1}
在这里插入图片描述
增量序列为{17,15,13,11,9,7,5,3,1}
在这里插入图片描述
增量序列为{101,91,81,71,61,51,41,31,21,11,1}
在这里插入图片描述
增量序列为{10001,5001,1001,851,351,301,251,201,151,101,51,1}
在这里插入图片描述

#include <stdio.h>
#include <malloc.h>
void ShellInsertSort(int arr[],int n,int d[]){
    for(int k=0;k<3;k++){
        for(int i=d[k]+1;i<=n;i++){
            arr[0]=arr[i];
            int j=i-d[k];
            for(;j>0&&arr[0]<arr[j];j-=d[k])
                arr[j+d[k]]=arr[j];
            arr[j+d[k]]=arr[0];
        }
    }
}

int main(){
    int n;
    scanf("%d",&n);
    int *a=(int*)malloc(sizeof(int)*n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    int d[]={5,3,1};
    ShellInsertSort(a,n,d);
    for(int i=1;i<=n;i++){
        if(i==1)
            printf("%d",a[i]);
        else printf(" %d",a[i]);
    }
}

选择排序

简单选择排序

在这里插入图片描述

#include <stdio.h>
#include <malloc.h>
void selection_sort(int arr[],int n){
    for(int i=1;i<=n-1;i++){
        int min=i;
        for(int j=i+1;j<=n;j++){
            if(arr[j]<arr[min])
                min=j;
        }
        int temp=arr[min];
        arr[min]=arr[i];
        arr[i]=temp;
    }
}
int main(){
    int n;
    scanf("%d",&n);
    int *arr=(int*)malloc(sizeof(int)*n);
    for(int i=1;i<=n;i++){
        scanf("%d",&arr[i]);
    }
    selection_sort(arr,n);
    printf("%d",arr[1]);
    for(int i=2;i<=n;i++){
        printf(" %d",arr[i]);
    }
}

在这里插入图片描述

#include <stdio.h>
#include <malloc.h>
void selection_sort(int arr[],int n){
	int temp;
    for(int i=0;i<n-1;i++){
        for(int j=i+1;j<n;j++){
            if(arr[i]>arr[j]){
                temp=arr[i];
                arr[i]=arr[j];
                arr[j]=temp;
            }
        }
    }
}
int main(){
    int n;
    scanf("%d",&n);
    int *arr=(int*)malloc(sizeof(int)*n);
    for(int i=0;i<n;i++){
        scanf("%d",&arr[i]);
    }
    selection_sort(arr,n);
    printf("%d",arr[0]);
    for(int i=1;i<n;i++){
        printf(" %d",arr[i]);
    }
}

归并排序

今天在做王道书归并排序的题目时才明白递归和迭代实现的归并排序的排序过程是不同的。

在递归实现中,归并排序使用分治的思想,通过递归地将数组划分为较小的子数组,并对子数组进行排序,最后再合并这些已排序的子数组来得到最终的排序结果。
而在迭代实现中,归并排序使用循环来模拟递归的过程,而不是通过函数调用和递归。迭代实现通常使用一个辅助数组来存储中间结果,而不是在递归过程中创建多个临时数组。
具体来说,在迭代实现中,将数组划分为长度为1的子数组,并进行两两合并。然后将合并后的结果再次两两合并,直到最终得到完全排序的数组。
迭代实现的优点是避免了递归调用的开销,可以在对大型数组排序时提供更好的性能。而递归实现则更直观和易于理解,但可能在处理大型数组时导致栈溢出或性能问题。

这是GPT给出的解释。

题目是排序{503,87,512,61,908,170,897,275,653,462}这个数组。

//递归的过程
{503 87 512 61 908 170 897 275 653 462} //初始数组
{503 87 512 61 908}  {170 897 275 653 462} //第一次划分
{503 87}{512 61 908} {170 897}{275 653 462}  //第二次划分
{503}{87} {512} {61 908}  {170} {897} {275} {653 462} //第三次划分
{503} {87} {512} {61} {908} {170} {897} {275} {653} {462}  //第四次划分
{87 503} {512} {61 908} {170 897} {275} {462 653}   //第一次归并
{87 503}  {61 512 908} {170 897} {275 462 653}  //第二次归并
{61 87 503 512 908}   {170 275 462 653 897}   //第三次归并
{61 87 170 275 462 503 512 653 897 908 }  //第四次归并

//迭代的过程
{503} {87} {512} {61} {908} {170} {897} {275} {653} {462} //第一次划分 
{87 503} {61 512} {170 908} {275 897} {462 653} //第一次归并
{61 87 503 512} {170 275 897 908} {462 653} //第二次归并
{61 87 170 275 503 512 897 908} {462 653} //第三次归并
{61 87 170 275 462 503 512 653 897 908} //第四次归并
 

王道课程中的手算归并排序都是默认按照迭代实现的,但给出的代码是递归实现的,这里容易造成误解,其实迭代和递归的过程是不一样的。

递归

在这里插入图片描述

#include <stdio.h>
#include <malloc.h>

void merge_sort(int arr[],int temp[],int low,int high){
    if(high-low<=1) return ;
    int mid=low+((high-low)>>1);
    merge_sort(arr,temp,low,mid);
    merge_sort(arr,temp,mid,high);
    for(int i=low,j=mid,k=low;k<high;k++){
        if(j==high||(i<mid&&arr[i]<=arr[j]))
            temp[k]=arr[i++];
        else temp[k]=arr[j++];      
    }
    for(int i=low;i<high;i++) arr[i]=temp[i];
    
}
int main(){
    int n;
    scanf("%d",&n);
    int *arr=(int*)malloc(sizeof(int)*n);
    int *temp=(int*)malloc(sizeof(int)*n);
    for(int i=0;i<n;i++){
        scanf("%d",&arr[i]);
    }
    merge_sort(arr, temp , 0 , n);
    printf("%d",arr[0]);
    for(int i=1;i<n;i++){
        printf(" %d",arr[i]);
    }
}
迭代

在这里插入图片描述

#include <stdio.h>
#include <malloc.h>
void merge_pass(int arr[],int temp[],int n,int length){
    for(int i=0;i<n;i+=2*length){
        int p1=i,p2=i+length,p3=0;
        while(p1<length+i&&p2<i+length*2&&p2<n){
            if(arr[p1]<=arr[p2])
                temp[i+p3++]=arr[p1++];
            else temp[i+p3++]=arr[p2++];
        }
        while(p1<n&&p1<i+length)
            temp[i+p3++]=arr[p1++];
        
        while(p2<n&&p2<i+2*length)
            temp[i+p3++]=arr[p2++];
        
    }
}
void merge_sort(int arr[], int n){
    int *temp=(int*)malloc(sizeof(int)*n);
    int length=1;
    while(length<n){
        merge_pass(arr,temp,n,length);
        length*=2;
        merge_pass(temp,arr,n,length);
        length*=2;
    }
}
int main(){
    int n;
    scanf("%d",&n);
    int *arr=(int*)malloc(sizeof(int)*n);
    for(int i=0;i<n;i++){
        scanf("%d",&arr[i]);
    }
    merge_sort(arr, n);
    printf("%d",arr[0]);
    for(int i=1;i<n;i++){
        printf(" %d",arr[i]);
    }
}

堆排序

在这里插入图片描述

#include <stdio.h>
#include <malloc.h>
void swap(int *a,int *b){
    *a=*a^*b;
    *b=*a^*b;
    *a=*a^*b;
}
void HeapAdjust(int arr[],int start,int end){
    int parent=start;
    int child=parent*2+1;
    while(child<=end){
        if(child+1<=end&&arr[child]<arr[child+1])
            child++;
        if(arr[child]<=arr[parent])
            return ;
        else {
            swap(&arr[child],&arr[parent]);
            parent=child;
            child=parent*2+1;
        }
    }
}
void HeapSort(int arr[],int n){
    for(int i=(n-2)/2;i>=0;i--)
        HeapAdjust(arr,i,n-1);
    for(int i=n-1;i>0;i--){
        swap(&arr[0],&arr[i]);
        HeapAdjust(arr,0,i-1);
    }
}
int main(){
    int n;
    scanf("%d",&n);
    int *arr=(int*)malloc(sizeof(int)*n);
    for(int i=0;i<n;i++){
        scanf("%d",&arr[i]);
    }
    HeapSort(arr, n);
    printf("%d",arr[0]);
    for(int i=1;i<n;i++){
        printf(" %d",arr[i]);
    }
}

树形选择排序(锦标赛排序)

在这里插入图片描述

#include <stdio.h>
#include <malloc.h>

void TreeSort(int arr[],int n){
    int nodeSize=n*2-1;              //满二叉树的非叶子结点数=叶子节点数*2-1
    int tree[nodeSize+1];           
    //填充叶子结点
    for(int i=n-1,j=0;i>=0;i--,j++){
        tree[nodeSize-j]=arr[i];
    }
    //填充非叶子结点
    for(int i=nodeSize-n;i>0;i--){
        tree[i]=tree[i*2]<tree[i*2+1]?tree[i*2]:tree[i*2+1];
    }

    
    int index=0;      //数组a的索引
    int minIndex=0;   //最小值的索引
    while(index<n){
        int min=tree[1];
        arr[index++]=tree[1];
        minIndex=nodeSize;
        while(tree[minIndex]!=min)
            minIndex--;
        tree[minIndex]=__INT_MAX__;
        while(minIndex>1){
            if(minIndex%2==0){
                tree[minIndex/2]=tree[minIndex]<tree[minIndex+1]?tree[minIndex]:tree[minIndex+1];
                minIndex=minIndex/2;
            }else {
                tree[minIndex/2]=tree[minIndex]<tree[minIndex-1]?tree[minIndex]:tree[minIndex-1];
                minIndex=minIndex/2;
            } 
        }
    }
}
int main(){
    int n;
    scanf("%d",&n);
    int *arr=(int*)malloc(sizeof(int)*n);
    for(int i=0;i<n;i++){
        scanf("%d",&arr[i]);
    }
    TreeSort(arr, n);
    printf("%d",arr[0]);
    for(int i=1;i<n;i++){
        printf(" %d",arr[i]);
    }
}

总结

排序方法性能比较
  • 直接插入排序:正序时时间复杂度最优,为 O ( n ) O(n) O(n);逆序时时间复杂度最差,为 O ( n ) O(n) O(n);平均时间复杂度为 O ( n 2 ) O(n^2) O(n2);稳定;原始序列基本有序时该方法好。
  • 折半插入排序:时间复杂度正序时最优,为 O ( n log ⁡ 2 n ) O(n\log_2n) O(nlog2n);逆序时最差,为 O ( n 2 ) O(n^2) O(n2);稳定
  • 希尔排序(缩小增量排序):平均时间复杂度为 O ( n ) O(n^) O(n),不稳定
  • 冒泡排序(改进后):正序时时间复杂度最优,为 O ( n ) O(n) O(n);逆序时最差,为 O ( n 2 ) O(n^2) O(n2);平均时间复杂度为 O ( n 2 ) O(n^2) O(n2) ;稳定
  • 快速排序:平均时间复杂度为 O ( n log ⁡ 2 n ) O(n\log_2n) O(nlog2n),平均时性能最优,正序或逆序时最差,为 O ( n 2 ) O(n^2) O(n2);有辅助栈,空间复杂度最差为 O ( n ) O(n) O(n),平均空间复杂度为 O ( log ⁡ 2 n ) O(\log_2n) O(log2n);不稳定,枢轴改进
  • 选择排序:时间复杂度为 O ( n 2 ) O(n^2) O(n2),原序列有序无序都如此;稳定
  • 堆排序:时间复杂度为 O ( n log ⁡ 2 n ) O(n\log_2n) O(nlog2n);不稳定
  • 链式基数排序:最好和最坏的时间复杂度都为 O ( d ( n + r d ) ) O(d(n+rd)) O(d(n+rd)),空间复杂度为 O ( r d ) O(rd) O(rd)
  • 归并排序:最好最坏时间复杂度为 O ( n log ⁡ 2 n ) O(n\log_2n) O(nlog2n),空间复杂度为 O ( n ) O(n) O(n),稳定
  • 内部排序方法分类:1.时间复杂度为 O ( n 2 ) O(n^2) O(n2)的简单排序方法;2.时间复杂度为 O ( n log ⁡ 2 n ) O(n\log_2n) O(nlog2n)的高效排序方法(比较法理论下界);3.时间复杂度为 O ( d ( n + r d ) ) O(d(n+rd)) O(d(n+rd))的基数排序方法
  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

能饮一杯吴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值