timsort的c++实现

timsort(优化后归并)

核心:提取降序数组升级为升序

数组本质都是部分有序的,

因此第一步:将所有部分降序数组全部翻转(这里直接逆序就好)

这一步模板:

void reverse(int q[],int l,int r)
{
    for(int i=l,j=r;i<=j;i++,j--)swap(q[i],q[j]);
}
void array_reverse(int q[],int N)
{
    if(N==1&&N==0)return;
    int i=1,l=0,tmp=0,stage_judge;
    if(q[0]<=q[1])stage_judge=1;//升序标记
    else  stage_judge=0;
    while(i<N)
    {
        if(q[i]>q[i+1])
        {
            if(stage_judge==1)stage_judge=0;
            ++i;
        }
        else if(q[i]<=q[i+1])
        {
            if(stage_judge==0)
            {
                if(tmp!=l-1)++l;
                reverse(q,l,i);
                tmp=i;
                stage_judge=1;
            }
            ++i;//前进一个
            l=i;//l=前进一位之后的i
        }
    }
}

核心:栈处理归并

先将所有已知的升序排列的压入总栈,

这一步:

void stack_check(int N)//对栈进行检验,并且要的是归并两个连续短区间
{
    int stack_pos1,stack_pos2,stack_pos3;
    int stack_length1,stack_length2,stack_length3;//1最顶,3最底层
    pop(stack_pos1,stack_length1);
    pop(stack_pos2,stack_length2);
    pop(stack_pos3,stack_length3);
    if(stack_length2<stack_length1||stack_length3<stack_length1+stack_length2)//x>y或者x+y>z
    {
        if(stack_length1>stack_length3)
        {
                push(stack_pos1,stack_length1);
                merge(stack_pos3, stack_length3,stack_pos2, stack_length2 );//对yz进行归并
​
        }
            else
        {
                    push(stack_pos3,stack_length3);
                    merge(stack_pos2,stack_length2,stack_pos1,stack_length1);//对xy进行归并
        }
           // cout<<endl<<endl<<"idx: "<<stack_idx<<endl;
        for(int i=0;i<N;i++)
        {
            cout<<q[i]<<" ";
        }
        cout<<endl;
        if(stack_idx>=2)stack_check(N);//递归检测
    }
    else//按照原先顺序再压进去
    {
        push(stack_pos3,stack_length3);
        push(stack_pos2,stack_length2);
        push(stack_pos1,stack_length1);
        cout<<endl<<endl;
    }
    return;
}

核心:最小分区长度在排序之前预先计算

➢ 归并过程低效的主要原因是大分区和小分区合并

while(stack_idx>=1)//输出阶段,这里就是检测是否正确归并入栈,没有归并
   {
        pop(stack_pos1,stack_length1);
        pop(stack_pos2,stack_length2);
       if(stack_pos1>stack_pos2)merge(stack_pos2,stack_length2,stack_pos1,stack_length1);
       else merge(stack_pos1,stack_length1,stack_pos2,stack_length2);
       for(int i=0;i<N;i++)
       {
           cout<<q[i]<<" ";
       }

timsort模板

#include<iostream>
using namespace  std;
const int M =10010;
int q[M];
int tmp[M];
int pos_stack[M];//存储下标
int length_stack[M];//存储长度
int stack_idx=-1;
void push(int pos,int length )
{
    pos_stack[++stack_idx]=pos;
    length_stack[stack_idx]=length;
}
void pop(int &tmp_pos,int &tmp_length)//给两个数赋值然后弄出去
{
    tmp_pos= pos_stack[stack_idx];
    tmp_length= length_stack[stack_idx];
    --stack_idx;
    return;
}
void reverse(int q[],int l,int r)
{
    for(int i=l,j=r;i<=j;i++,j--)swap(q[i],q[j]);
}
void array_reverse(int q[],int N)
{
    if(N==1&&N==0)return;
    int i=1,l=0,tmp=0,tem_l=0,stage_judge;
    if(q[0]<=q[1])stage_judge=1;//升序标记
    else  stage_judge=0;
    while(i<N)
    {
        if(q[i]>q[i+1])
        {
            if(stage_judge==1)
            {
                stage_judge=0;//之前是升序这里突然降序了
            }
            ++i;
        }
        else if(q[i]<=q[i+1])
        {
            if(stage_judge==0)
            {
                if(tmp!=l-1)++l;
                reverse(q,l,i);
                tmp=i;
                stage_judge=1;
            }
            ++i;//前进一个
            l=i;//l=前进一位之后的i
        }
    }
}
void merge(int pos1,int length1,int pos2,int length2)
{
    int r=pos2+length2-1;//最右端
    int l=pos1;//最左端
    //归并部分
    int mid=pos1+length1-1;
    int k = 0, i = l, j = pos2 ;
    while (i <= mid && j <= r)//这里由于递归,每一个小数组都归并好了,归并最后的大数组
        if (q[i] <= q[j]) tmp[k ++ ] = q[i ++ ];//归并,结果合并到tmp,
        else tmp[k ++ ] = q[j ++ ];
    while (i <= mid) tmp[k ++ ] = q[i ++ ];//赋值剩下的i
    while (j <= r) tmp[k ++ ] = q[j ++ ];//赋值剩下的j
    for (i = l, j = 0; i <= r; i ++, j ++ ) q[i] = tmp[j];
    push(pos1,length1+length2);//合并完之后进行压栈
}
void stack_check(int N)//对栈进行检验,并且要的是归并两个连续短区间
{
    int stack_pos1,stack_pos2,stack_pos3;
    int stack_length1,stack_length2,stack_length3;//1最顶,3最底层
    pop(stack_pos1,stack_length1);
    pop(stack_pos2,stack_length2);
    pop(stack_pos3,stack_length3);
    if(stack_length2<stack_length1||stack_length3<stack_length1+stack_length2)//x>y或者x+y>z
    {
        if(stack_length1>stack_length3)
        {
                push(stack_pos1,stack_length1);
                merge(stack_pos3, stack_length3,stack_pos2, stack_length2 );//对yz进行归并
​
        }
            else
        {
                    push(stack_pos3,stack_length3);
                    merge(stack_pos2,stack_length2,stack_pos1,stack_length1);//对xy进行归并
        }
           // cout<<endl<<endl<<"idx: "<<stack_idx<<endl;
        for(int i=0;i<N;i++)
        {
            cout<<q[i]<<" ";
        }
        cout<<endl;
        if(stack_idx>=2)stack_check(N);//递归检测
    }
    else//按照原先顺序再压进去
    {
        push(stack_pos3,stack_length3);
        push(stack_pos2,stack_length2);
        push(stack_pos1,stack_length1);
        cout<<endl<<endl;
    }
    return;
}
//归并搞定
int main() {
    int N;
    cin >> N;
    int stack_pos1,stack_pos2,stack_pos3;
    int stack_length1,stack_length2,stack_length3;
    for (int i = 0; i < N; i++) {
        cin >> q[i];
    }
    array_reverse(q, N - 1);//没问题了,别动!
    int l=0;
    for(int i = 0; i < N; i++) {
        if(q[i]>q[i+1])
        {
            push(l,i-l+1);
​
            l=i+1;
        }
    }//这里完成将栈压入
    //接下来就是找最大的,然后合并
    cout<<endl<<endl;
    for(int i=0;i<N;i++)
    {
        cout<<q[i]<<" ";
    }
    cout<<endl;
    if(stack_idx>=2)stack_check(N);
    while(stack_idx>=1)//输出阶段,这里就是检测是否正确归并入栈,没有归并
   {
        pop(stack_pos1,stack_length1);
        pop(stack_pos2,stack_length2);
       if(stack_pos1>stack_pos2)merge(stack_pos2,stack_length2,stack_pos1,stack_length1);
       else merge(stack_pos1,stack_length1,stack_pos2,stack_length2);
       for(int i=0;i<N;i++)
       {
           cout<<q[i]<<" ";
       }
   }
    return 0;
}//23         2 4 7 8 23 19 16 14 13 12 10 20 18 17 15 11 0 5 6 1 3 21 22

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值