STL算法我实现之rotate


STL在rotate上的优化是极尽其所能的。分别对前向访问,双向访问,随机访问的数据结构实现了三个版本的rotate。下面是自己按照对三种算法的理解,自己进行的实现。实现中我尽力避免使用C++的特性,从而以后可以在纯C的代码中使用。

下面是我使用到的数据结构,单向链表与双向链表,用于实现算法和验证算法的正确性:

//单链表节点
typedef struct Node* Link;
struct Node{
    int value;
    Link next;
    Link forward(Link& i)
    {
        i=i->next;
        return i;
    }
    void swap(Link& i)
    {
        int temp=i->value;
        i->value=this->value;
        this->value=temp;
    }
};
 
typedef struct BiNode* BiLink;
struct BiNode{
    int value;
    BiLink next;
    BiLink prev;
    BiLink forward(BiLink& i)
    {
        i=i->next;
        return i;
    }
    BiLink backward(BiLink& i)
    {
        i=i->prev;
        return i;
    }
    void swap(BiLink& i)
    {
        int temp=i->value;
        i->value=this->value;
        this->value=temp;
    }
};

版本一:forward iterator,即类单向链表上的rotate

//forward iterator,即类单向链表
void forwardRotate(Link head,Link middle)
{
    Link i=middle;
    while(true)
    {
        head->swap(i);
        head->forward(head);
        i->forward(i);
        if(head==middle)
        {
            if(i==NULL) return ;            //如果前后两指针同时到达末尾,则结束
            middle=i;                       //如果前者先到达末尾,则将i作为middle,继续rotate
        }
        else if(i==NULL)
            i=middle;                       //如果后者先到达末尾,则将middle作为i,继续rotate
    }
}

另附上注释的图像版以帮助理解:
stl-rotate.png

版本二:bidirection iterator,即类双向链表上的rotate

这个版本的算法很容易理解,即是分段进行反转,之后对左右数据进行反转,代码如下:

void reverse(BiLink first,BiLink last)
{
    while(first!=last &&first!=last->backward(last))
    {
        last->swap(first);
        first->forward(first);
    }
}
 
void bidirectionRotate(BiLink first,BiLink middle,BiLink last)
{
    reverse(first,middle);
    reverse(middle,last);
    reverse(first,last);
}

版本三:random access iterator,即类数组上的rotate

该版本的效率无疑是最高的,当然算法因为涉及到有关群论的知识所以有点难以理解。其理论支持详见:数组循环移位问题

自己实现版本的代码如下:

//求最大公约数
int gcd(int m,int n)
{
    int t;
    while(n!=0)
    {
        t=m%n;
        m=n;
        n=t;
    }
    return m;
}
//循环移位
void rotate_cycle(int array[],int len,int initial,int shift)
{
    int value=array[initial];
    int first=initial;
    int next=initial+shift;
    while(next!=initial)
    {
        array[first]=array[next];
        first=next;
        next=(next+shift)%len;
    }
    array[first]=value;
}
 
void randomRotate(int array[],int middle,int len)
{
    int n=gcd(len,middle);
    while(n--)
        rotate_cycle(array,len,n,middle);
}

最后附上我自己的测试代码:

int main()
{
    int len=20;
    srand(time(0));
    //单向访问链表的rotate
    Link head=new Node;
    head->value=25;
    cout<<head->value<<"\t";
    Link p=head;
    Link middle;
    for(int i=0;i<len;i++)
    {
        Link next=new Node;
        p->next=next;
        next->value=rand()%200;
        cout<<next->value<<"\t";
        if(i==len/4*3)
            middle=p;
        p=p->next;
    }
    cout<<endl;
    p->next=NULL;
    forwardRotate(head,middle);	
    p=head;
    while(p!=NULL)
    {
        cout<<p->value<<"\t";
        p=p->next;
    }
    cout<<endl;

    //双向链表的rotate
    BiLink bihead=new BiNode;
    bihead->value=25;
    cout<<bihead->value<<"\t";
    BiLink bip=bihead;
    BiLink bimiddle;
    for(int i=0;i<len;i++)
    {
        BiLink binext=new BiNode;
        bip->next=binext;
        binext->prev=bip;
        binext->value=rand()%200;
        cout<<binext->value<<"\t";
        if(i==len/4)
            bimiddle=bip;
        bip=bip->next;
    }
    cout<<endl;
    BiNode end;
    bip->next=&end;
    end.prev=bip;
    bidirectionRotate(bihead,bimiddle,&end);	
    bip=bihead;
    while(bip!=&end)
    {
        cout<<bip->value<<"\t";
        bip=bip->next;
    }
    cout<<endl;

    int array[len];
    for(int i=0;i<len;i++)
    {
        array[i]=rand()%200;
        cout<<array[i]<<"\t";
    }	
    cout<<endl;
    randomRotate(array,len/3,len);
    for(int i=0;i<len;i++)
        cout<<array[i]<<"\t";
    cout<<endl;
    return 0;
}

OK,大致如此了。三个版本的rotate,极至的优化手段,这也许就是STL的魅力所在吧。

本文作者 : cyningsun
本文地址https://www.cyningsun.com/04-25-2011/stl-rotate.html
版权声明 :本博客所有文章除特别声明外,均采用 CC BY-NC-ND 3.0 CN 许可协议。转载请注明出处!

# STL