几大内部排序算法(二)

这儿是我的笔记,希望大家可以友好交流!!谢谢#__#

这一篇就记录两个都运用分治思想的排序算法,快速排序和归并排序。

(一)快速排序:
内部排序无非用插入排序,希尔排序,快速排序,大容量的输入推荐使用希尔排序和快速排序,数量小的插入排序更合适,当然为了一下就能写好,用冒泡和选择排序也可以(哈哈哈)。快排的平均复杂度是O(NlogN),是几大排序中最快的。

基本算法:
1:如果S中的元素是0和1,则返回
2:取s中的任一元素作为枢纽元
3:将S-{V}分成2个不相交集合,S1= {x属于S-{V}|x

void Quick_Sort(int *A,int N)
{
    if(A==NULL || N <= 0)
    {
        printf("输入数组有误\n");
        exit(0);
    }
    Quick(A,0,N-1);
}

三数中值,并返回枢纽元

int Medium_WithThree(int* A,int left,int right)
{
    int center = (left + right) >> 1;
    if(A[left] > A[right])
        Swap(A,left,right);
    if(A[left] > A[center])
        Swap(A,left,center);
    if(A[center] > A[right])
        Swap(A,center,right);
    /**以上三步其实已经A[left] < A[center] < A[right],接下来再把中值放到倒数第二个*/
    Swap(A,center,right-1);
    return A[right-1];
}
void Swap(int *A ,int a,int b)
{
    int tmp ;
    tmp = A[a];
    A[a] = A[b];
    A[b] = tmp;

}
void Quick(int *A,int left,int right)
{
    int shuniu = 0;
    int i =0, j =0;
    if(right - left  >= 3)//有三个元素时以上时采用快排,界限一般定位10,因为10以下用插入比较合适,不知道为什么只有3才很合适
    {
        shuniu = Medium_WithThree(A,left,right);
        i = left; j = right-1;
//j这是中枢的位置用于和i换,Swap(A,i,right-1),所以不参与中途交换;
        while(1)
        {
            while(A[++i] < shuniu){}
            while(A[--j] > shuniu){}
            if(i < j)
            {
                Swap(A,i,j);
            }
            else
                break;
        }
        Swap(A,i,right-1);
        Quick(A,left,i-1);
        Quick(A,i+1,right);
    }
    else
    {
        Insert_Sort(A,left,right);
    }

}

注意上面一定要让++i,–j,否则当遇到和枢纽元相等时,程序就进入死循环了。

(二)归并排序
归并排序,平均复杂度也是O(NlogN),但是由于合并2个表时需要附加的内存,还要花费时间将数据拷贝到临时数组,再拷贝回去,所以一般采用快排不用归并但是归并的是外部排序的基础思想。

驱动例程:提前分配好数组,避免每次递归都要malloc

void Merge_Sort(int *A,int N)
{
    int* tmp = NULL;
    if(N < 0 || A == NULL)
    {
        printf("数组不合法\n");
        return ;
    }
    else
    {
        tmp = (int*)malloc(sizeof(int)*N);
        if(tmp!=NULL)
        {
            Merge(A,tmp,0,N-1);
            free(tmp);
        }
    }
}

实际的递归函数

void Merge(int *A,int* tmp,int left,int right)
{
    int center;
    if(left < right)
    {
        center = (right+left) / 2;
        Merge(A,tmp,left,center);
        Merge(A,tmp,center+1,right);
        Merge1(A,tmp,left,center,right);
    }
}

合并函数:注意这里的tmppos一定要从left开始,不能从0开始

void Merge1(int* A,int* tmp,int left,int leftend,int rightend)
{
    int right = leftend+1;
    /**这里的tmp一定不能用0表示*/
    int tmppos = left;
    while(left <=leftend && right <= rightend )
    {
        if(A[left] < A[right])
            tmp[tmppos++] =  A[left++];
        else
            tmp[tmppos++] = A[right++];

    }
    while(left<=leftend)
    {
        tmp[tmppos++] = A[left++];
    }
    while(right<=rightend)
    {
        tmp[tmppos++] = A[right++];
    }

    while(--tmppos>=0)
    {
        A[tmppos] = tmp[tmppos];
    }
}

两个运用了分治思想的也好了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值