首页 > 代码库 > 数据结构与算法-链表反转带头节点

数据结构与算法-链表反转带头节点

1.输入一个链表的头结点,反转该链表,并返回反转后链表的头结点。
链表结点定义如下:    
struct ListNode
{
      int       m_nKey;
      ListNode* m_pNext;
};
分析:这是一道广为流传的微软面试题。由于这道题能够很好的反应出程序员思维是否严密,在微软之后已经有很多公司在面试时采用了这道题。

为了正确地反转一个链表,需要调整指针的指向。与指针操作相关代码总是容易出错的,因此最好在动手写程序之前作全面的分析。在面试的时候不急于动手而是一开始做仔细的分析和设计,将会给面试官留下很好的印象,因为在实际的软件开发中,设计的时间总是比写代码的时间长。与其很快地写出一段漏洞百出的代码,远不如用较多的时间写出一段健壮的代码。

最容易想到的第一种方法就是重新建立一个单链表newList,每次将list中的第一个结点放到newList后面。(头插法)

int ReverseSinglyListNode(ListNode *list)
{
    ListNode  *newList;    //新链表的头结点
    LNode       *p,*q;       //指向list的第一个结点,也就是要摘除的结点
    p=List;
    
    //参数为空或者内存分配失败则返回NULL
    if (p == NULL || (newList = (ListNode *)malloc(sizeof(LNode))) == NULL)
    {
        return NULL;
    }                       
    //初始化newList
    newList->next = NULL;
                            
    //依次将list的第一个结点放到newList的第一个结点位置
    while (p->next != NULL)
    {        
        q = p->next;                   
        newList->next = p->next;       //头插法
        p=newList->next;
        p=q;
    }
                            
    //原头结点应该释放掉,并返回新头结点的指针
    free(p);
    return newList;
}

 

第二种方法是每次都将原第一个结点之后的那个结点放在list后面,下图是原始的单链表。

技术分享
为了反转这个单链表,我们先让头结点的next域指向结点2,再让结点1的next域指向结点3,最后将结点2的next域指向结点1,就完成了第一次交换,顺序就变成了Header-结点2-结点1-结点3-结点4-NULL,然后进行相同的交换将结点3移动到结点2的前面,然后再将结点4移动到结点3的前面就完成了反转,思路有了,就该写代码了:

int  ReverseSinglyLinkedList(ListNode *list)
{
    LNode   *p = NULL;
    LNode   *q = NULL;
           
    if (list == NULL) return NULL;
    p = list->next;
    while (p->next != NULL)
    {
        q = p->next;
        p->next = q->next;
        q->next = list->next;
        list->next = q;
    }
    return list;
}

 

数据结构与算法-链表反转带头节点