快速排序

学习之后,自己练习手写一下排序算法,加深印象

原理:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序的目的。

#define MAXSIZE 10
#include <stdio.h>
struct a{
    int array[MAXSIZE];    //数组用于存储排序数据 
    int length;           //用于存储数组长度信息, 
};

void init_array(struct a *L){   //初始化数组 
    int i;
    L->length = MAXSIZE-1;
    for (i=1;i<=L->length;i++){     //索引为0的项留作备用 
        scanf("%d",&(L->array[i]));
    }
}

void swap(struct a *L,int i,int j){   //交换数组项 
    int temp = L->array[i];
    L->array[i] = L->array[j];
    L->array[j] = temp;
}

void print(struct a *L){    //打印数组项 
    int i;
    for (i=1;i<=L->length;i++){
        printf("%d ",L->array[i]);
    }
}

int Partition(struct a *L, int low, int high){   //将一个序列划分为两个子序列 
    int middleValue; 
    middleValue = L->array[low];      //选取序列的第一项为枢纽值 
    while(low < high){                  
        while(low < high && middleValue <= L->array[high]){
            high--;       //从序列的尾部向前,依次和枢纽值比较,若当前项比枢纽值小,则退出循环 
        }
        swap(L,low,high);     //交换当前项和枢纽值 

        while(low < high && middleValue >= L->array[low]){
            low++;      //从序列的开头向后,依次枢纽值比较 ,若当前项比枢纽值大,则退出循环 
        }
        swap(L,low,high);   //交换当前项和枢纽值 
    }
    return low;   //最终low等于high,返回枢纽值 
}

void QSort(struct a*L, int low, int high){
    int middle;     
    if (low < high){ 
        middle = Partition(L,low,high);   //将序列划分为两个子序列,返回中点索引 
        QSort(L,low,middle-1);          //对值较小的子序列递归排序 
        QSort(L,middle+1,high);        //对值较大的子序列递归排序 
    } 
}

void QuickSort(struct a *L){   //排序算法 
    QSort(L,1,L->length);
} 

int main(){
    struct a List;
    init_array(&List);
    printf("排序前:");
    print(&List);
    QuickSort(&List);
    printf("\n排序后:");
    print(&List);
    return 0;
}

Partition函数的作用就是选取一个记录,例如第一个关键字50,然后将其放到一个位置,使得它左边的值都比它小,右边的值都比它大,这样的关键字称为枢纽
第一次划分子序列后,结果如下:
这里写图片描述

算法时间复杂度:O(nlogn)
这里写图片描述

优化
1.优化选取枢纽值

middleValue = L->array[low];

不再选取序列的第一项,而是选取三个数里中间大小的那个数

int m = low + (high -low)/2;
if (L->array[low] > L->array[high]){
    swap(L,low,high);
}
if (L->array[m] > L->array[high]){
    swap(L,m,high);
}
if (L->array[m] > L->array[low]){
    swap(L,low,m);
}
//排序过后保证了,枢纽值取得是三个数里面中间大小的数
pivotkey = L->array[low]
....   

2.优化不必要的交换

int Partition(struct a *L, int low, int high){   //将一个序列划分为两个子序列 
    int middleValue; 
    middleValue = L->array[low];      //选取序列的第一项为枢纽值
    while(low < high){                  
        while(low < high && middleValue <= L->array[high]){
            high--;       //从序列的尾部向前,依次和枢纽值比较,若当前项比枢纽值小,则退出循环 
        }
        L->array[low] = L->array[high];   //替换而不是交换

        while(low < high && middleValue >= L->array[low]){
            low++;      //从序列的开头向后,依次枢纽值比较 ,若当前项比枢纽值大,则退出循环 
        }
        L->array[high] = L->array[low];  //替换而不是交换
    }
    L->array[low] = middleValue;   //将枢纽值替换回L->array[low] 
    return low;   //最终low等于high,返回枢纽值 
}

3优化递归次数(尾递归优化)

void QSort(struct a*L, int low, int high){
    int middle;     
    While (low < high){ 
        middle = Partition(L,low,high);   //将序列划分为两个子序列,返回中点索引 
        QSort(L,low,middle-1);          //对值较小的子序列递归排序 
        low = middle+1             //尾递归 
    } 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值