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