用一个高效的算法将一个单链表 L = (a1,a2,.. an-1,an)变换成L=(a1,an,a2,an-1,....)

基本思路:
该变换将L的后半部分倒插进前半部分,为了实现高效,可以将链表后半部分倒置后插入前半部分

  1. 找到后半部分的开头指针:设置两个指针slow和fast,slow增加一步,fast增加两步,则fast到达表尾时slow刚好为中间的位置。
  2. 倒置后半部分:可以用头插法或者设置prev,cur,next三个指针直接修改指针指向

使用c语言实现:


void main(){
    
    
    pList head,tail,slow,fast;
    buildListWithHead(&head,12);
    slow=head->next;
    fast=head->next;
    while(fast->next->next){
    
    
        slow=slow->next;
        fast=fast->next->next;
    }
    transverse(head);
    printf("\n中间的点: %d\n",slow->it);
    //latter记录后半部分的开头指针,cur和follow为头插法倒置辅助指针
    pList latter=slow->next,cur=latter, follow;
    slow->next=NULL;
    //头插法将后半部分的链表倒置
    while(cur){
    
    
        follow=cur->next;
        cur->next=slow->next;
        slow->next=cur;
        cur=follow;
    }
    //倒置后需要latter为最后一个指针,需要重新指向为后半部分开头指针
    latter=slow->next;
    slow->next=NULL;
    //遍历前半部分插入倒置后的后半部分
    //cur重新指向head,使用tmp作为始终指向后半部分链表的辅助指针
    cur=head->next;
    follow=latter;
    pList tmp=latter->next;
    while(cur&&follow){
    
    
        follow->next=cur->next;
        cur->next=follow;
        cur=cur->next->next;
        follow=tmp;
        if(tmp) tmp=tmp->next;//在follow和cur到达null前tmp已经到达NUll
    }
    //遍历转置后的链表
    transverse(head);

}

其他辅助方法和结构体:


typedef struct LinkList
{
    
    
    int it;
    struct LinkList *next;
} LinkList, *pList;

//建立一个带有头结点的单链表,传入二级指针L,在函数中修改指针
void buildListWithHead(pList *L, int len)
{
    
    
    *L = (pList)malloc(sizeof(LinkList));
    pList p1 = *L;
    for (int i = 0; i < len; ++i)
    {
    
    
        pList tmp = (pList)malloc(sizeof(LinkList));
        tmp->it = rand() % 50;
        tmp->next = NULL;
        p1->next = tmp;
        p1 = tmp;
    }
}
//遍历链表
void transverse(pList head){
    
    
    printf("遍历: ");
    pList cur=head->next;
    while(cur){
    
    
        printf("%d,",cur->it);
        cur=cur->next;
    }
}

猜你喜欢

转载自blog.csdn.net/Wind_waving/article/details/110877904