反转链表
题目:
定义一个函数,输入一个链表的头结点,反转该链表并输出反转后链表的头结点。链表结点定义如下:
struct ListNode{
int m_nKey,
ListNode * m_pNext;
}
思路:
为了正确地反转一个链表,需要调整链表中指针的方向。为了将复杂的过程说清楚,这里借助于下面的这张图片。
上面的图中所示的链表中,h、i和j是3个相邻的结点。假设经过若干操作,我们已经把h结点之前的指针调整完毕,这个结点的m_pNext都指向前面的一个结点。接下来我们把i的m_pNext指向h,此时结构如上图所示。
从上图注意到,由于结点i的m_pNext都指向了它的前一个结点,导致我们无法在链表中遍历到结点j。为了避免链表在i处断裂,我们需要在调整结点i的m_pNext之前,把结点j保存下来。
即在调整结点i的m_pNext指针时,除了需要知道结点i本身之外,还需要i的前一个结点h,因为我们需要把结点i的m_pNext指向结点h。同时,还需要实现保存i的一个结点j,以防止链表断开。故我们需要定义3个指针,分别指向当前遍历到的结点、它的前一个结点及后一个结点。故反转结束后,新链表的头的结点就是原来链表的尾部结点。尾部结点为m_pNext为null的结点。
代码实现:
public class ListNode {
public int data;
public ListNode next;
}
public ListNode reverseList(ListNode pHead){ ListNode pReversedHead = null; //反转过后的单链表存储头结点 ListNode pNode = pHead; //定义pNode指向pHead; ListNode pPrev = null; //定义存储前一个结点 while(pNode != null){ ListNode pNext = pNode.next; //定义pNext指向pNode的下一个结点 if(pNext==null){ //如果pNode的下一个结点为空,则pNode即为结果 pReversedHead = pNode; } pNode.next = pPrev; //修改pNode的指针域指向pPrev pPrev = pNode; //将pNode结点复制给pPrev pNode = pNext; //将pNode的下一个结点复制给pNode } return pReversedHead; }
小结:
这道题考查我们是否真正的理解了单链表的结构,以及在反转单链表时对指针的修改。
扩展:
我们知道这个题其实是可以用递归实现使单链表变成反转链表。
代码实现:
public ListNode reverseList3(ListNode pHead){
if(pHead==null || pHead.next == null){ //如果没有结点或者只有一个结点直接返回pHead
return pHead;
}
ListNode pNext = pHead.next; //保存当前结点的下一结点
pHead.next = null; //打断当前结点的指针域
ListNode reverseHead = reverseList3(pNext); //递归结束时reverseHead一定是新链表的头结点
pNext.next = pHead; //修改指针域
return reverseHead;
}