快速排序

思路:
1、先从数列中取出一个数作为基准数。
2、分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
3、再对左右区间重复第二步,直到各区间只有一个数。
例如:
将low指向头,high指向尾,将基准值放在tmp中,一次快排过程,如图:
这里写图片描述
源代码:

int Partion(int *arr, int low, int high)//第一次快排
{
    int tmp = arr[high];//选high作为基准
    while (low < high)
    {
        while (low < high && arr[low] <= tmp)
        {
            low++;
        }
        if (low >= high)//high和low相遇
        {
            break;
        }
        else
        {
            arr[high] = arr[low];
        }
        while (low < high && arr[high] >= tmp)
        {
            high--;
        }
        if (low >= high)//high和low相遇
        {
            break;
        }
        else
        {
            arr[low] = arr[high];
        }
    }
    arr[high] = tmp;//arr[low] = tmp;
    return high;
}

快排递归调用:

void Quick(int *arr, int start, int end)
{
    int par = Partion(arr, start,end);
    if (par > start+1)
    {
        Quick(arr,start,par-1);
    }
    if (par < end - 1)
    {
        Quick(arr,par+1,end);
    }
}
void Quick_Sort1(int *arr, int len)//快速排序递归
{
    Quick(arr,0,len-1);
}

快排非递归调用:
快排非递归调用是用栈来保存每次low和high的值,low先入栈,high就先出栈。

void Quick_Sort(int *arr, int len)//快速排序非递归
{
    int lenstack = (int)(log10((double)len) / log10((double)2));
    int *stack = (int *)malloc(sizeof(int)*2*lenstack);
    assert(stack != NULL);
    int top = 0;
    int low = 0;
    int high = len - 1;
    int par = Partion(arr,low,high);
    if (par > low + 1)
    {
        stack[top++] = low;//low先入栈
        stack[top++] = par - 1;
    }
    if (par < high - 1)
    {
        stack[top++] = par + 1;//par + 1先入栈
        stack[top++] = high;
    }//第一次入栈
    while (top > 0)
    {
        high = stack[--top];//high先出栈
        low = stack[--top];//low后出栈
        int par = Partion(arr, low, high);
        if (par > low + 1)
        {
            stack[top++] = low;//low先入栈
            stack[top++] = par - 1;
        }
        if (par < high - 1)
        {
            stack[top++] = par + 1;//par + 1先入栈
            stack[top++] = high;
        }
    }
    free(stack);
    stack = NULL;
}

主函数:

int main()
{
    int arr[] = {3,2,4,1,6,5,0,8,9,7};
    int len = sizeof(arr) / sizeof(arr[0]);
    Show(arr,len);
    Quick_Sort1(arr,len);
    //Mearge_Sort(arr,len);
    Show(arr, len);
    return 0;
}

关于快排的优化,会在后面进行。。。。。。
今天学到了三种快排的优化(也不算是优化吧,)
第一种:随机去基准
这种方法增加了快排的实用性,不仅针对特殊的,也可以对常规的排序。

int Partion(int *arr, int low, int high)
{
    int tmp = arr[low];//选基准
    while (low < high)
    {
        while (low < high && tmp <= arr[high])
        {
            high--;
        }
        if (low >= high)
        {
            break;
        }
        else
        {
            arr[low] = arr[high];
        }
        while (low < high && arr[low] <= tmp)
        {
            low++;
        }
        if (low >= high)
        {
            break;
        }
        else
        {
            arr[high] = arr[low];
        }
    }
    arr[low] = tmp;
    return low;
}
//随机选取基准
void Swap(int *arr, int start, int end)
{
    int tmp;
    tmp = arr[start];
    arr[start] = arr[end];
    arr[end] = tmp;
}
void Quick(int *arr, int start, int end)
{
    Swap(arr,start,rand()%(end-start)+start);//end = rand()%(end-start)+start随机选基准
    int par = Partion(arr, start, end);
    if (par > start + 1)
    {
        Quick(arr, start, par-1);
    }
    if (par < end - 1)
    {
        Quick(arr, par+1, end);
    }
}
void Quick_Sort1(int *arr, int len)
{
    Quick(arr, 0, len - 1);
}
void Show(int *arr, int len)
{
    for (int i = 0;i < len;++i)
    {
        printf("%d ", arr[i]);
    }
    printf("\n");
}
int main()
{
    int arr[] = { 2,5,3,2,5,5,7,5,6 };
    //int arr[] = {9,8,7,6,5,4,3,2,1};
    int len = sizeof(arr) / sizeof(arr[0]);
    Show(arr, len);
    Quick_Sort1(arr, len);
    Show(arr, len);
    return 0;
}

第二种:三位取中法
选的基准更贴合实际,省去了很多麻烦,时间复杂度也减小了。

void Median_Of_Three(int *arr, int start, int mid, int end)//三数取中法
{
    if (arr[mid] > arr[end])
    {
        Swap(arr, mid, end);
    }
    if (arr[mid] > arr[start])
    {
        Swap(arr, mid, start);
    }
    if (arr[start] > arr[end])
    {
        Swap(arr, start, end);
    }
}
void Quick(int *arr, int start, int end)
{
    Median_Of_Three(arr, start, start + (end - start) / 2, end);
    int par = Partion(arr, start, end);
    int left = par - 1;
    int right = par + 1;
    if (par > start + 1)
    {
        Quick(arr, start, par-1);
    }
    if (par < end - 1)
    {
        Quick(arr, par+1, end);
    }
}
void Quick_Sort1(int *arr, int len)
{
    Quick(arr, 0, len - 1);
}
void Show(int *arr, int len)
{
    for (int i = 0;i < len;++i)
    {
        printf("%d ", arr[i]);
    }
    printf("\n");
}
int main()
{
    int arr[] = { 2,5,3,2,5,5,7,5,6 };
    //int arr[] = {9,8,7,6,5,4,3,2,1};
    int len = sizeof(arr) / sizeof(arr[0]);
    Show(arr, len);
    Quick_Sort1(arr, len);
    Show(arr, len);
    return 0;
}

第三种:基准聚焦法
这种方法才真正算是对快排的优化。当遇到与基准的值相同时,不用再对它进行比较,可将它靠近基准的旁边。
void Foucs_Nums(int *arr, int par, int *left, int *right, int start, int end)//遇到与基准一样的数字,把它们聚集到一起

void Foucs_Nums(int *arr, int par, int *left, int *right, int start, int end)//遇到与基准一样的数字,把它们聚集到一起
{
    int Parleftindex = par - 1;
    for (int i = par - 1;i >= start;i--)//2,5,3,2,5,5,7,5,6    从基准左边找
    {
        if (arr[i] == arr[par])
        {
            if (i != Parleftindex)
            {
                Swap(arr, i, Parleftindex);
                Parleftindex--;
            }
            else
            {
                Parleftindex--;//Parleftindex右边的数是基准,不用交换
            }
        }
    }
    int Parrightindex = par + 1;
    for (int j = par + 1;j <= end;j++)//从基准右边找
    {
        if (arr[j] == arr[par])
        {
            if (j != Parrightindex)
            {
                Swap(arr, j, Parrightindex);
                Parrightindex++;
            }
            else
            {
                Parrightindex++;//Parrightindex左边的数是基准,不用交换
            }
        }
    }
    *left = Parleftindex;
    *right = Parrightindex;
}
void Quick(int *arr, int start, int end)
{
    //Swap(arr,start,rand()%(end-start)+start);//end = rand()%(end-start)+start
    //Median_Of_Three(arr, start, start + (end - start) / 2, end);
    int par = Partion(arr, start, end);
    int left = par - 1;
    int right = par + 1;
    Foucs_Nums(arr, par, &left, &right, start, end);
    if (par > start + 1)
    {
        Quick(arr, start, left);
    }
    if (par < end - 1)
    {
        Quick(arr, right, end);
    }
}
void Quick_Sort1(int *arr, int len)
{
    Quick(arr, 0, len - 1);
}
void Show(int *arr, int len)
{
    for (int i = 0;i < len;++i)
    {
        printf("%d ", arr[i]);
    }
    printf("\n");
}
int main()
{
    int arr[] = { 2,5,3,2,5,5,7,5,6 };
    //int arr[] = {9,8,7,6,5,4,3,2,1};
    int len = sizeof(arr) / sizeof(arr[0]);
    Show(arr, len);
    Quick_Sort1(arr, len);
    Show(arr, len);
    return 0;
}

这就是我知道的关于快排的优化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值