单链表进阶学习 三段

从尾到头打印单链表:

思路:

  1. 实际意义就是逆序打印单链表;
  2. 利用栈的操作,先进后出,实现逆序打印效果。

(注:不建议直接对单链表进行反转操作。这样会破坏链表本身的结构,在做题和练习的时候可以尝试,但在工作中考虑到链表的重复使用,最好习惯使用栈数据结构的思想来操作)


演示栈:

  1. 要单个取出栈元素的操作
import java.util.Stack;public class TextStackDemo {// 演示栈的操作public static void main(String[] args) {// TODO Auto-generated method stub// 输入“new stack()”,快捷键“ctrl+1”Stack<String> stack = new Stack<>();// 新建一个stack栈,标注键入String类型的数据// 入栈stack.add("1");//可以用push();stack.add("2");stack.add("3");// 键入栈stack三个string类型的数据// 入栈完成// 出栈// pop()直接代表出栈操作System.out.println(stack.pop());// 一次操作出栈一个数据}
}

2.将栈元素一次性取出的操作

import java.util.Stack;public class TextStackDemo {// 演示栈的操作public static void main(String[] args) {// TODO Auto-generated method stub// 输入“new stack()”,快捷键“ctrl+1”Stack<String> stack = new Stack<>();// 新建一个stack栈,标注键入String类型的数据// 入栈stack.add("1");stack.add("2");stack.add("3");// 键入栈stack三个string类型的数据// 入栈完成// 出栈// pop()直接代表出栈操作while (stack.size() > 0) {System.out.println(stack.pop());// 一次操作出栈一个数据}}
}

接下来进入正题:

用栈的思想解决单链表的逆序打印:

import java.util.Stack;public class SingleLinkedListDemo {public static void main(String[] args) {// TODO Auto-generated method stub 第一阶段测试代码// 创建节点HeroNode hero1 = new HeroNode(1, "呼保义", "宋江");HeroNode hero2 = new HeroNode(2, "玉麒麟", "卢俊义");HeroNode hero3 = new HeroNode(3, "智多星", "吴用");HeroNode hero4 = new HeroNode(4, "入云龙", "公孙胜");HeroNode hero5 = new HeroNode(5, "大刀", "关胜");// 创建单链表SingleLinkedList singleLinkedList = new SingleLinkedList();singleLinkedList.add(hero1);singleLinkedList.add(hero2);singleLinkedList.add(hero3);singleLinkedList.add(hero4);singleLinkedList.add(hero5);// 测试单链表逆序功能// 显示System.out.println("原链表:");singleLinkedList.list();System.out.println();System.out.println("逆序输出的链表:");reversePrint(singleLinkedList.GetHead());/** //测试单链表反转功能 // 显示 System.out.println("原链表:"); singleLinkedList.list();* * System.out.println(); System.out.println("反转后的链表:");* reverseList(singleLinkedList.GetHead()); singleLinkedList.list();* * * // 加入操作* * // singleLinkedList.add(hero1); // // singleLinkedList.add(hero2); // //* singleLinkedList.add(hero3); // // singleLinkedList.add(hero4); // //* singleLinkedList.add(hero5);* * singleLinkedList.addByOrder(hero1);* * singleLinkedList.addByOrder(hero2);* * singleLinkedList.addByOrder(hero4);* * singleLinkedList.addByOrder(hero3);* * singleLinkedList.addByOrder(hero5);* * // 修改操作 HeroNode newHeroNode = new HeroNode(5, "写轮眼", "卡卡西");* singleLinkedList.update(newHeroNode);* * // 显示 System.out.println("删除前:"); singleLinkedList.list();* * // 修改操作 singleLinkedList.del(1); System.out.println("删除后:");* singleLinkedList.list(); // 获取单链表节点的个数* System.out.println(GetNumber(singleLinkedList.GetHead()));* * HeroNode res = findLastIndexNode(singleLinkedList.GetHead(), 1);// 倒数第1个* System.out.println(); System.out.println("单链表中倒数第index个节点    " + res);*/}// 逆序打印单链表public static void reversePrint(HeroNode head) {if (head.next == null) {return;// 空链表,无法打印}// 创建一个栈,将各节点压入栈中Stack<HeroNode> stack = new Stack<HeroNode>();HeroNode cur = head.next;// 遍历需要的辅助变量while (cur != null) {stack.push(cur);cur = cur.next;// 后移,好压入下一个节点}// 出栈while (stack.size() > 0) {System.out.println(stack.pop());}}// 反转链表public static void reverseList(HeroNode head) {// 老样子,先判断链表是否为空if (head.next == null || head.next.next == null) {return;}// 定义一个辅助变量,帮助遍历整个链表HeroNode cur = head.next;HeroNode next = null;// 指向当前节点【cur】的下一个节点HeroNode reverseHead = new HeroNode(0, "", "");// 遍历原来的链表// 遍历一个节点就将其取出,放在新建链表的最前端while (cur != null) {next = cur.next;// 暂时保存当前节点的下一个节点cur.next = reverseHead.next;// cur节点的下一个节点指向新链表的最前端reverseHead.next = cur;// 将cur连接到新的链表上cur = next;// cur后移}// 将原链表的头节点的next指向rereverseHead的下一个节点,实现链表的反转head.next = reverseHead.next;}// 1.查找单链表中倒数第index个节点// 2.编写一个方法接收head节点,同时接受一个index(index数值代表单链表的倒数第index个节点)// 3.将链表遍历一遍,得到有效节点总数(GetNumber)// 4.单链表有效节点总数为size,直接遍历size-index个节点// 5.如果找到了这个节点就返回该节点,否则就返回NULLpublic static HeroNode findLastIndexNode(HeroNode head, int index) {// 如果链表为空返回NULLif (head.next == null) {return null;}// 第一次遍历得到单链表的节点个数int size = GetNumber(head);// 第二次遍历单链表,这次直接遍历size-index个节点,这就是要求的值// 在这里要做一个index的校验if (index <= 0 || index > size) {return null;}// 定义一个辅助变量,指向第一个有效节点(头节点后的第一个节点)HeroNode cur = head.next;// for循环定位到倒数index个节点for (int i = 0; i < size - index; i++) {cur = cur.next;}return cur;}//获取单链表节点的个数(如果带头结点,计数时要取消头结点的计数,因为头节点不存储数据)public static int GetNumber(HeroNode head) {if (head.next == null) {return 0;}int number = 0;// 定义一个辅助变量HeroNode cur = head.next;// 这里就是没有统计头结点的微操作while (cur != null) {number++;cur = cur.next;}return number;}
}//定义一个SingleLinkedList(单链表),管理英雄
class SingleLinkedList {// 一开始要初始化一个头节点,保持不动否则会找不到剩下的节点,***不存放具体数据private HeroNode head = new HeroNode(0, "", "");// no初始化为0,姓名和称号也不写// 返回头节点public HeroNode GetHead() {return head;}// 添加节点到单向链表// 当不考虑编号顺序时:// 把节点添加进去的操作是首先找到当前链表的最后一个节点,next域原本是NULL,要把next域指向新添的节点public void add(HeroNode heroNode) {// 由于头节点不能动,所以需要辅助变量HeroNode temp = head;// temp是辅助变量一开始指向头节点,因为单向链表不是顺序存储,所以每一次找最后一个节点都需要遍历整个链表// 开始遍历while (true) {// 死循环if (temp.next == null) {// 找到链表的尾节点了break;}// 如果当前节点不是末节点// temp后移一位temp = temp.next;// 要清楚temp是一个移动辅助变量,每遍历到一个不是尾节点的点temp就会指向当前节点的下一个节点}// 当退出这个死循环的时候,temp就指向了单链表的尾节点// 这个时候就可以把尾节点的next域指向传入的新节点,这个新传入的节点就连上了temp.next = heroNode;}// 增添节点,按照顺序显示出来// 如果已经有这个编号,则添加失败并给出提示public void addByOrder(HeroNode heroNode) {// heroNode为传入的新节点// 由于头节点不能动,所以需要辅助变量// 单链表要添加节点,temp一定是指向要插入位置的前一个节点,然后temp.next就指向新节点,这样第一步就完成了HeroNode temp = head;boolean flag = false;// 判断要添加的节点是否已存在while (true) {if (temp.next == null) {break;}if (temp.next.no > heroNode.no) {break;} else if (temp.next.no == heroNode.no) {flag = true;// 说明已经有了break;} else {temp = temp.next;// 如果上述情况都不符合的话,那么继续遍历找下一个节点}}// 退出循环的时候要看flag的值if (flag) {System.out.printf("已有编号%d,添加失败~~~\n", heroNode.no);} else {// 可以插入到链表中,temp后移heroNode.next = temp.next;// 新节点的next域指向下一个节点temp.next = heroNode;// 前一个节点的next域指向新节点}}//修改节点的信息// 根据编号no来修改称号和姓名,编号no不动(如果编号改变就相当于添加操作了)public void update(HeroNode newHeroNode) {// 判断链表是否为空if (head.next == null) {System.out.println("链表为空~~~");return;}// 找到需要修改的节点// 根据编号no来修改节点信息// 定义一个辅助变量HeroNode temp = head.next;boolean flag = false;// 标识是否找到这个节点while (true) {if (temp == null) {// 这里和之前不一样,表示已经遍历完这个链表了(无残留,去干净)break;} else if (temp.no == newHeroNode.no) {// 表示已经找到要删除的节点flag = true;break;}temp = temp.next;}// 退出循环以后,根据flag的值来判断if (flag) {// flag=true;表示找到了要修改的点temp.name = newHeroNode.name;temp.nickname = newHeroNode.nickname;}// 还有一种情况就是没有找到要修改的点else {System.out.println();System.out.printf("没有找到编号为%d 的好汉,不能删除												

单链表进阶学习 三段相关推荐

  1. 单链表进阶学习 二段

    单链表进阶学习 二段 单链表的反转 思路: 定义一个新节点,reserveHead=new HeroNode(); 利用辅助变量cur遍历原来的链表,每遍历一个节点就将其取出,放在新建链表的最前端:( ...

  2. 线性表中的尾插法单链表的学习

    #include <stdio.h> #include <malloc.h>/*** 线性表中的尾插法单链表的学习 *//*** 人类*/ typedef struct Per ...

  3. 数据结构-单链表进阶之快慢指针原理(快速查找法)

    面试题:快速找到未知长度单链表的中间节点? 这个问题的解决方法分为普通方法和高级方法. 1.普通方法即我们大家都能一下子想到的,首先遍历一遍获取总长度L,然后再次遍历循环至L/2即可:时间复杂度为: ...

  4. 《数据结构》c语言版学习笔记——单链表结构(线性表的链式存储结构Part1)

    线性表的链式存储结构 数据结构系列文章 第二章 单链表结构 文章目录 线性表的链式存储结构 前言 一.单链表的建立 代码 二.单链表的读取 代码 三.单链表的插入 代码 四.单链表的删除 代码 五.单 ...

  5. 日常学习随笔-数组、单链表、双链表三种形式实现队列结构的基本操作(源码注释)...

    一.队列结构(本文侧重于源码实现,基础理论不多赘述) 和栈一样,队列(queue)也是表,然而使用队列是在一端插入数据,在另一端删除数据.这里插入就是入队(enqueue),删除就是(dequeue) ...

  6. 单链表操作2-单链表A拆分成奇数和偶数值单链表B和C(个人学习笔记,仅供参考)

    单链表A拆分成奇数和偶数值单链表B和C 题目要求 单链表结点定义 函数接口定义 测试程序样例 输入样例 输出样例 答案 题目要求 在一个带头结点的单链表A中,头指针为a,设计算法SplitList ( ...

  7. 单链表操作10-带头结点的单链表逆置(个人学习笔记,仅供参考)

    带头结点的单链表逆置 题目要求 单链表结点定义 函数接口定义 测试程序样例 输入样例 输出样例 答案 题目要求 设计算法Reverse( ),将带头结点的单链表A逆置,要求利用原有链表的链点,最后输出 ...

  8. 数据结构学习(C++)——单链表应用(一元多项式【1】) (转)

    数据结构学习(C++)--单链表应用(一元多项式[1]) (转)[@more@] 总算到了这里,这时,你会很得意的说,辛辛苦苦学的单链表总算知道能干点什么了.但是很不幸,如果你和我一样看的是那本书,到 ...

  9. Go 学习笔记(80)— Go 标准库 container/list(单链表、双链表)

    列表是一种非连续存储的容器,由多个节点组成,节点通过一些变量记录彼此之间的关系.列表有多种实现方法,如单链表.双链表等. ​ 在 Go 语言中,将列表使用 container/list 包来实现,内部 ...

最新文章

  1. java string 转化为date
  2. 通过蜜罐技术获取攻击者手机号、微信号【网络安全】
  3. C#之foreach语句
  4. 都说性能调优难?玩转这3款工具,让你秒变“老司机”!
  5. 微服务升级_SpringCloud Alibaba工作笔记0022---Nacos之Group分组方案
  6. CSS选择器优先级排列
  7. 轻松解决ArcGIS Pro 安装中文汉化包或离线帮助文档时报错“指定路径为空”
  8. 内容创作者周刊:第4期
  9. linux 改成utc时间_linux – 如何将时区设置为UTC-8
  10. 【腾讯敏捷转型No.7】QQ邮箱如何通过敏捷成为行业第一
  11. 目标检测数据集:直升机(1)
  12. Cesium中的相机—旋转矩阵
  13. 协同过滤推荐之基于近邻协同过滤(一)
  14. RTL8812AU/21AU and RTL8814AU drivers and linux driver
  15. 广东省工业和信息化厅财政专项资金支持项目验收管理办法通知
  16. 开源一个自用的Android IM库,基于Netty+TCP+Protobuf实现。
  17. Android 让注册商标R往上移
  18. 今个大言不惭下,讲一讲嘛是文化属性,有啥用?
  19. BIM二级考试第17期第一题用revit2016系统库中现场浇筑楼梯平台的bug
  20. Flash Player 10 中的RTMFP(实现P2P)

热门文章

  1. 微信小程序利用缓存提高接口请求性能
  2. 仿微博国际版首页点击显示分组列表(popupwindow悬浮阴影效果)
  3. OSG模拟鼠标事件影响操纵器
  4. key map 模糊查找_lua脚本语言批量删除模糊查询的key
  5. ubuntu intellij java_在Linux上,安装Intellij IDEA进行Scala开发
  6. 第10章 springboot是什么
  7. Tomcat部署Web应用
  8. ”盒模型“之如何防止边框和内边距把元素撑开
  9. Jquery加载默认值
  10. Intellij IDEA 新建一个EJB工程(三)