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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构与算法-链表反转带头节点相关的知识,希望对你有一定的参考价值。

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;
}

 













以上是关于数据结构与算法-链表反转带头节点的主要内容,如果未能解决你的问题,请参考以下文章

什么叫带头结点的链表? 什么叫不带头结点的链表?

C实现头插法和尾插法来构建单链表(不带头结点)

单链表的反转非递归算法

每天一道算法题(java数据结构与算法)——>反转链表

单向链表的构建以及翻转算法_图文详解

带头节点的双向链表