链表系列文章(三)

上一篇讨论了链表相关的几个有趣的问题,这一篇主要讨论与反转链表有关的问题

基本数据结构:

struct ListNode {
    int var;
    ListNode *next;
    ListNode( int v = 0 ) : var(v), next(NULL) { }
};

1.  反转链表

方法一:堆栈法,利用栈后进先出的特性,将链表节点依次入栈,然后弹出并修改next指针

时间复杂度O(n),空间复杂度O(n)

1 ListNode *reverseList(ListNode *head) {
2     if(!head || !head->next) return head;
3     ListNode newhead(-1), *h = &newhead;
4     std::vector<ListNode *> s;
5     for( ; head; head = head->next ) s.push_back(head);
6     while(!s.empty()) { h->next = s.back(); s.pop_back(); h = h->next; }
7     h->next = NULL;
8     return newhead.next;
9 };

方法二:头插法,创建一个新的头节点,然后遍历链表节点,将每个节点依次插入到头节点后

时间复杂度O(n),空间复杂度O(1)

 1 ListNode *reverseList(ListNode *head) {
 2     if(!head || !head->next) return head;
 3     ListNode newhead(-1), *h = &newhead, *temp = NULL;
 4     while(head) {
 5         temp = head->next;
 6         head->next = h->next;
 7         h->next = head;
 8         head = temp;
 9     }
10     return newhead.next;
11 };

方法三:前插法,把链表分为两部分,依次把后一部分的节点前插到前一部分

时间复杂度O(n),空间复杂度O(1)

 1 ListNode *reverseList(ListNode *head) {
 2     if(!head || !head->next) return head;
 3     ListNode *prev = head, *curr = prev->next, *next = NULL;
 4     prev->next = NULL;
 5     while(curr) {
 6         next = curr->next;
 7         curr->next = prev;
 8         prev = curr;
 9         curr = next;
10     }
11     return prev;
12 };

2.  反转链表的[m, n]区间的节点

和反转链表的区别是,我们必须保存反转后的尾指针,使其指向第n+1个节点

方法一:堆栈法,相比上个问题,只需保存一下第n+1个节点地址即可,不再赘述

方法二:头插法,时间复杂度O(n),空间复杂度O(1)

ListNode *reverseList( ListNode *list, int m, int n ) {
    ListNode *head = new ListNode();
    ListNode *phead = head;
    ListNode *curr, *prev;
    phead->next = list;
    n -= m;//需要反转的次数
    while( --m ) { phead = phead->next; } //phead->next指向第m个节点
    prev = phead->next;//prev指向反转区间的尾部
    curr = prev->next;//指向反转区间的头部
    while( n-- ) {
        prev->next = curr->next;//这里的prev->next其实就是尾指针!!!
        curr->next = phead->next;
        phead->next = curr;//头插法
        curr = prev->next;
    }
    return head->next;
}   

3. 给定两个指针begin和end,反转begin->...->end之间的节点,返回反转后的倒数第一个节点指针

方法参考 2.  反转链表的[m, n]区间的节点

 1 ListNode* reverseList(ListNode *prev, ListNode *begin, ListNode *end) {
 2     ListNode *end_next = end->next;
 3     for (ListNode *p = begin, *cur = p->next, *next = cur->next;
 4         cur != end_next;
 5         p = cur, cur = next, next = next ? next->next : NULL) {
 6         cur->next = p;
 7     }
 8     begin->next = end_next;//这里的begin->next其实就是尾指针!!!
 9     prev->next = end;
10     return begin;
11 }

4. 小结

反转链表本身比较简单,但是当要区间反转时,一定要牢记,不能忘了尾指针!!!

由于本人水平有限,文中难免有不当和错误之处,欢迎大家批评指正,愿共同进步!!!

时间: 2024-10-28 20:07:22

链表系列文章(三)的相关文章

JVM系列文章(三):Class文件内容解析

作为一个程序员,仅仅知道怎么用是远远不够的.起码,你需要知道为什么可以这么用,即我们所谓底层的东西. 那到底什么是底层呢?我觉得这不能一概而论.以我现在的知识水平而言:对于Web开发者,TCP/IP.HTTP等等协议可能就是底层:对于C.C++程序员,内存.指针等等可能就是底层的东西.那对于Java开发者,你的Java代码运行所在的JVM可能就是你所需要去了解.理解的东西. 我会在接下来的一段时间,和读者您一起去学习JVM,所有内容均参考自<深入理解Java虚拟机:JVM高级特性与最佳实践>(

链表系列文章(一)

参考 http://www.cnblogs.com/skywang12345/p/3561803.html在此致谢! 采用C++,实现了单链表和双向循环链表: 1. 单链表 1 #ifndef SINGLE_LIST_H 2 #define SINGLE_LIST_H 3 4 #ifndef INT_MAX 5 #define INT_MAX 2147483647 6 #define INT_MIN (-INT_MAX - 1) 7 #endif 8 #define ERROR INT_MIN

链表系列文章(四)

上一篇讨论了链表的反转问题,这一篇讨论链表排序的问题 1. 排序两个有序链表 比较简单,属于归并排序,不再赘述 时间复杂度O(n), 空间复杂度O(1) 1 ListNode *mergeList( ListNode *list1, ListNode *list2 ) { 2 if(!list1 || !list2) return list1 ? list1 : list2; 3 ListNode res(-1), *phead = &res; 4 while(list1 && l

C#网络编程系列文章(三)之TcpListener实现异步TCP服务器

原创性声明 本文作者:小竹zz 本文地址http://blog.csdn.net/zhujunxxxxx/article/details/44258719 转载请注明出处 本文介绍 TcpListener 类提供一些简单方法,用于在阻止同步模式下侦听和接受传入连接请求. 可使用 TcpClient 或 Socket 来连接 TcpListener. 可使用 IPEndPoint.本地 IP 地址及端口号或者仅使用端口号,来创建 TcpListener. 可以将本地 IP 地址指定为 Any,将本

《神经网络和深度学习》系列文章三:sigmoid神经元

出处: Michael Nielsen的<Neural Network and Deep Leraning>,点击末尾“阅读原文”即可查看英文原文. 本节译者:哈工大SCIR硕士生 徐伟 (https://github.com/memeda) 声明:我们将在每周一,周四,周日定期连载该书的中文翻译,如需转载请联系[email protected],未经授权不得转载. “本文转载自[哈工大SCIR]微信公众号,转载已征得同意.” 使用神经网络识别手写数字 感知机 sigmoid神经元 神经网络的

TCP和UDP通信(C#网络编程) ---- 系列文章

文章系列目录 C#网络编程系列文章(一)之Socket实现异步TCP服务器 C#网络编程系列文章(二)之Socket实现同步TCP服务器 C#网络编程系列文章(三)之TcpListener实现异步TCP服务器 C#网络编程系列文章(四)之TcpListener实现同步TCP服务器 C#网络编程系列文章(五)之Socket实现异步UDP服务器 C#网络编程系列文章(六)之Socket实现同步UDP服务器 C#网络编程系列文章(七)之UdpClient实现异步UDP服务器 C#网络编程系列文章(八)

【微信小程序开发?系列文章六】生命周期和路由

这篇文章理论的知识比较多一些,都是个人观点,描述有失妥当的地方希望读者指出. [微信小程序开发•系列文章一]入门 [微信小程序开发•系列文章二]视图层 [微信小程序开发•系列文章三]数据层 [微信小程序开发•系列文章四]模块化 [微信小程序开发•系列文章五]主界面 [微信小程序开发•系列文章六]生命周期和路由 整个微信小程序从打开到关闭,整个过程可以分为很多阶段或者说状态,这一整段的过程,我们称之为小程序的生命周期.而周期中的每种不同的状态,到另一个状态的过度和转化,是需要一个触发机制的,这种机

C#网络编程系列文章(一)之Socket实现异步TCPserver

原创性声明 本文作者:小竹zz 本文地址http://blog.csdn.net/zhujunxxxxx/article/details/44258719 转载请注明出处 文章系列文件夹 C#网络编程系列文章(一)之Socket实现异步TCPserver C#网络编程系列文章(二)之Socket实现同步TCPserver C#网络编程系列文章(三)之TcpListener实现异步TCPserver C#网络编程系列文章(四)之TcpListener实现同步TCPserver C#网络编程系列文章

C#网络编程系列文章(八)之UdpClient实现同步UDP服务器

原创性声明 本文作者:小竹zz 本文地址http://blog.csdn.net/zhujunxxxxx/article/details/44258719 转载请注明出处 文章系列目录 C#网络编程系列文章(一)之Socket实现异步TCP服务器 C#网络编程系列文章(二)之Socket实现同步TCP服务器 C#网络编程系列文章(三)之TcpListener实现异步TCP服务器 C#网络编程系列文章(四)之TcpListener实现同步TCP服务器 C#网络编程系列文章(五)之Socket实现异