面试题-单链表反转

问题:定义一个函数,输入一个链表的头结点,反转该链表并输出反转后链表的头结点。

一 非递归算法:

     假设有链表A->B->C->D->E->F->G。在反转链表过程中的某一阶段,其链表指针指向为:A<-B<-C<-D  E->F->G。也就是说在结点D之前的所有结点都已经反转,而结点D后面的结点E开始的所有结点都没有反转。这样D跟E之间存在了断裂。我们如果要实现链表的反转,会有以下几个重要步骤:

  1. D->E变为D->C,指针反转
  2. 指针往后移动一个,操作下一个结点E
  3. 结合1.2我们发现需要操作3个指针,分别是C,D,E。

    因此可以考虑存储C/D/E三个结点的指针,通过这三个结点的指针实现反转。


代码:

    

ListNode* ReverseList(ListNode* pHead) //第一种方法
{
    ListNode* pNode=pHead;//当前结点
    ListNode* pPrev=NULL;//当前结点的前一个结点
    ListNode* pReversedHead=NULL;//反转链表头结点
    while(pNode!=NULL)
    {
        ListNode* pNext=pNode->m_pNext;
        if(pNext==NULL)//如果当前结点的下一个结点为空,那么反转链表的头结点就是当前结点。
            pReversedHead=pNode;

        pNode->m_pNext=pPrev;//当前结点指向前一个结点

        pPrev=pNode;//pPrev和pNode往前移动。
        pNode=pNext;//这里要使用前面保存下来的pNext,不能使用pNode->m_pNext
    }
    return pReversedHead;//返回反转链表头指针。
}

ListNode* ReverseList2(ListNode* pHead)//第二种方法:比较简洁的算法
{
    ListNode* pNode=pHead;//当前结点
    ListNode* pPrev=NULL;//当前结点的前一个结点
    while(pNode!=NULL)
    {
        ListNode* pNext=pNode->m_pNext;
        pNode->m_pNext=pPrev;//当前结点指向前一个结点

        pPrev=pNode;//pPrev和pNode往前移动。
        pNode=pNext;//这里要使用前面保存下来的pNext,不能使用pNode->m_pNext
    }
    return pPrev;//返回反转链表头指针。
}
 
 
测试代码:
 
 
    
#include<iostream>
#include<stdlib.h>
#include<stack>
using namespace std;

//链表结构
struct ListNode
{
    int m_nValue;
    ListNode* m_pNext;
};

//创建一个链表结点
ListNode* CreateListNode(int value)
{
    ListNode *pNode=new ListNode();
    pNode->m_nValue=value;
    pNode->m_pNext=NULL;
    return pNode;

}

//遍历链表中的所有结点
void PrintList(ListNode* pHead)
{
    ListNode *pNode=pHead;
    while(pNode!=NULL)
    {
        cout<<pNode->m_nValue<<" ";
        pNode=pNode->m_pNext;
    }
    cout<<endl;
}

//往链表末尾添加结点
/*
注意这里pHead是一个指向指针的指针,在主函数中一般传递的是引用。
因为如果要为链表添加结点,那么就会修改链表结构,所以必须传递引用才能够保存修改后的结构。
*/
void AddToTail(ListNode** pHead,int value)
{
    ListNode* pNew=new ListNode();//新插入的结点
    pNew->m_nValue=value;
    pNew->m_pNext=NULL;

    if(*pHead==NULL)//空链表
    {
        *pHead=pNew;
    }
    else
    {
        ListNode* pNode=*pHead;
        while(pNode->m_pNext!=NULL)
            pNode=pNode->m_pNext;
        pNode->m_pNext=pNew;
    }

}



void main()
{
    //创建结点
    ListNode* pNode1=CreateListNode(1);//创建一个结点
    PrintList(pNode1);//打印
    //往链表中添加新结点
    AddToTail(&pNode1,2);//为链表添加一个结点
    AddToTail(&pNode1,3);//为链表添加一个结点
    AddToTail(&pNode1,4);//为链表添加一个结点
    AddToTail(&pNode1,5);//为链表添加一个结点
    AddToTail(&pNode1,6);//为链表添加一个结点
    AddToTail(&pNode1,7);//为链表添加一个结点
    //打印链表
    PrintList(pNode1);//打印
    //反转链表
    ListNode* pReversedHead=ReverseList(pNode1);
    PrintList(pReversedHead);//打印

    system("pause");

}

二 递归算法
   

在递归算法中的做法是:

1找到最后一个节点和倒数第二个节点,把最后一个节点设为头节点的后继

2反转这两个节点

3倒数第三个和第四个节点重复执行步骤2

其中注意,链表是以节点后继为NULL结束的,在更改指针的过程中要把改后的节点后继改为NULL

代码:

  1. void Inversion_Recursion(ListNode* p,ListNode* Head)  
  2. {  
  3.     if(p->next==NULL)  
  4.     {  
  5.         Head->next=p;  
  6.         return;//找到最后一个节点  
  7.     }  
  8.     Inversion_Recursion(p->next,Head);  
  9.     p->next->next=p;//反转节点  
  10.     p->next=NULL;//第一个节点反转后其后继应该为NULL  
  11. }  

你可能感兴趣的:(面试题,单链表)