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

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;
}
时间: 2024-07-29 09:16:34

数据结构与算法-链表反转带头节点的相关文章

数据结构与算法-链表反转

1.输入一个链表的头结点,从尾到头反过来输出每个结点的值.链表结点定义如下:struct ListNode{      int       m_nKey;      ListNode* m_pNext;};分析:这是一道很有意思的面试题.该题以及它的变体经常出现在各大公司的面试.笔试题中.看到这道题后,第一反应是从头到尾输出比较简单.于是很自然地想到把链表中链接结点的指针反转过来,改变链表的方向.然后就可以从头到尾输出了. 接下来的想法是从头到尾遍历链表,每经过一个结点的时候,把该结点放到一个栈

数据结构与算法-链表的基本操作---ShinPans

//链表操作:建立.插入.删除.查找.倒置.删除等基本操作 #include<stdio.h> #include<stdlib.h> typedef  struct LNode {       int data;       structLNode *next; }LNode,*Llist; LNode *creat_head();//创建一个空表 void creat_list(LNode *,int);//创建一个长度为n的线性链表 void insert_list(LNode

链表算法-链表前面插入节点

链表算法-链表前面插入节点

数据结构与算法(c++)——反转链表

算法概述:要求实现将一条单向链表反转并考虑时间复杂度. 算法分析: 数组法(略): 将列表元素逐个保存进数组,之后再逆向重建列表 点评:实现逻辑最简单,需要额外的内存开销. 移动指针: 通过三个指针逐个从链表头开始逐一反转链表元素的指针 点评:不需要额外的内存开销,会改变原始链表. 递归: 以递归的方式首先找到链表尾部,再逐一反转指针 点评:不需要额外的内存开销,不会改变原始链表. 算法实现: 构建链表结构 /* 节点结构 */ struct NODE { int data; struct NO

数据结构和算法--链表一之单向链表的简单实现

链表在我们java中也是一种基础的数据结构,可以理解成是一种和数组同级的数组结构,正如我们所知,在我们使用这集合ArrayList和LinkedList的时候,总会学习底层数组实现的ArrayList和双向链表实现的LinkedList的区别.在这里,我们将要讲说的是单向链表的简单实现,让我们体会一下链表在实现增删改查的时候是怎么样的一个操作,在和前边涉及到的数组的增删改查进行对比,得到我们学习的结论,数组的增删效率低于链表结构,查改效率高于链表结构! 什么叫做单向链表,我们可以理解为一个一个节

数据结构和算法-链表

链表分类 单向链表 双向链表 优势: 删除某个节点更加高效, 可以快速找到前驱节点 可以方便的在某个节点前插入元素 循环链表 当要处理的数据具有环形结构的时候, 适合循环链表. 如约瑟夫环问题 双向循环链表 数组的缺点是大小固定, 一旦声明长度就要占用连续的内存空间, 当空间不够用时更换更大的空间, 此时就需要将原数组的所有数据迁移过去, 比较费时. 链表则可以动态扩容. 数组在查询上可以更快, 链表在插入和删除上更快, 为了结合数组和链表的优点, 有同时使用的情况, 比如一个网站的用户注册,

javascript数据结构与算法--二叉树(插入节点、生成二叉树)

javascript数据结构与算法-- 插入节点.生成二叉树 二叉树中,相对较小的值保存在左节点上,较大的值保存在右节点中 /* *二叉树中,相对较小的值保存在左节点上,较大的值保存在右节点中 * * * */ /*用来生成一个节点*/ function Node(data, left, right) { this.data = data;//节点存储的数据 this.left = left; this.right = right; this.show = show; } function sh

数据结构——线性表——链表反转

链表反转有两种常见方式.下面从图中详细解释.其中带有部分核心代码,最后上完整代码. 迭代法 //首先定义三个变量    PNODE pre = NULL;    PNODE now = pHead->pNext;    PNODE next = NULL; next = now->pNext;//先保存下一个节点 now->pNext = pre;//当前节点的next指针指向前一个节点 pre = now;//前一个节点赋值为当前节点 now = next;//当前节点赋值为下一个节点

单链表一[带头节点链表]

单链表实现分带头节点链表和不带头节点链表: 使用头文件如下: struct LinkNode {     void *x;      struct LinkNode *next; }; 一,带头节点的链表: 1,链表创建 程序说明: 1)函数调用形式:szyu_link_create0("AA", "BB", NULL);其中NULL结尾是在for循环的判断结束条件为x == NULL.使用NULL可以是for循环正常退出 2)程序先创建头节点head,并初始化he