数据结构--链表
一、链表
(一)链表介绍
1) 链表是有序存储,以节点的方式来存储,是链式存储结构
2) 每个节点包含 data 域(用来存储数据), next 域: 指向下一个节点(next中存储了要指向节点的内存地址)
3) 如图: 链表的各个节点不一定是连续存储.
4) 链表分带头节点的链表和没有头节点的链表, 根据实际的需求来确定
。头结点是指data域为空的节点,只有指向下一个节点的next域。
链表在内存中的存储形式: 链表的逻辑形式:
(二)单向链表的应用
在以下应用中,涉及到对链表的遍历时,需要将头结点赋值给一个辅助节点temp(因为头结点不能动),使用temp=temp.next来后移节点
1、向链表中添加节点。分为两种情况:
1)按添加语句的输入顺序添加节点:直接将节点添加到链表尾部。只需要使链表尾节点的next指向要添加的节点即可
代码实现如下
1 /** 2 * 将新节点加入链表 3 * 当不考虑编号时 4 * 思路:1、遍历链表,找到next=null的尾节点 5 * 2、将尾节点的next指向新节点 6 * @param heroNode 需要添加的新节点 7 */ 8 public void addNode(HeroNode heroNode){ 9 //遍历链表,找到结尾,在结尾处加入新的节点 10 HeroNode temp=headNode;//头结点不能动,需要辅助变量来遍历 11 while (true){ 12 if (temp.next == null) { 13 break; 14 } 15 //将节点后移 16 temp=temp.next; 17 } 18 //将新节点加到尾部 19 temp.next=heroNode; 20 }
2)按节点中的数据顺序添加节点:需要按照编号的顺序进行添加。
思路:遍历链表,将本节点的下个节点的编号(no1)(因为单向链表只有一个指向下个节点的next,无法指向上一个节点)与要添加节点的编号(no2)进行比较,
若no1>no2(按升序进行添加)则添加。
添加方式:新节点.next=temp.next
temp.next=新节点
代码实现如下:
1 /** 2 第二种方式在添加英雄时,根据排名将英雄插入到指定位置(如果有这个排名, 则添加失败, 并给出提示 3 * @param heroNode 4 */ 5 public void addNodeSort(HeroNode heroNode){ 6 //对链表进行遍历 7 HeroNode temp=headNode; 8 boolean flag=false; 9 while (true){ 10 if (temp.next == null) { 11 break; 12 } 13 //如果有这个排名, 则添加失败, 并给出提示 14 if (temp.next.no==heroNode.no){ 15 flag=true; 16 break; 17 } 18 if ( heroNode.no<temp.next.no){ 19 break; 20 } 21 temp=temp.next; 22 } 23 if (flag){ 24 System.out.printf("已有此编号%d,无法加入\n",heroNode.no); 25 }else { 26 heroNode.next=temp.next; 27 temp.next=heroNode; 28 } 29 }
2、删除节点
若当前节点的next指向的节点为要删除的节点,则执行
//使当前节点的next指向下下个节点,完成对下个节点的删除 temp.next=temp.next.next;
代码实现如下:
1 /** 2 * 根据no删除节点 3 */ 4 public void deleteNode(int no){ 5 HeroNode temp=headNode; 6 boolean flag=false; 7 if (temp.next==null){ 8 return; 9 } 10 while (true){ 11 //已经到达尾节点,跳出循环 12 if (temp.next == null) { 13 break; 14 } 15 //如果当前节点的next指向的下个节点为要删除的节点 16 if (no==temp.next.no){ 17 flag=true; 18 break; 19 } 20 temp=temp.next; 21 } 22 if (flag){ 23 //使当前节点的next指向下下个节点,完成对下个节点的删除 24 temp.next=temp.next.next; 25 }else { 26 throw new RuntimeException("该节点不存在"); 27 } 28 }
3、遍历链表
代码实现如下
1 /** 2 * 遍历链表 3 */ 4 public void showLists(){ 5 //先判断链表是否为空 6 if (headNode.next == null) { 7 System.out.println("链表为空"); 8 return; 9 } 10 HeroNode temp=headNode.next;// 11 while (true){ 12 //当前节点为链表尾 13 if (temp== null) { 14 break; 15 } 16 //输出当前节点的信息 17 System.out.println(temp); 18 //节点后移 19 temp=temp.next; 20 } 21 }
(三)双向链表的应用
管理单向链表的缺点分析:
- 1) 单向链表, 查找的方向只能是一个方向, 而双向链表可以向前或者向后查找。
- 2) 单向链表不能自我删除, 需要靠辅助节点 , 而双向链表, 则可以自我删除。
双向链表中的节点由三部分构成:pre域(指向上一个节点的内存地址)+data域(存储数据)+next域(指向下一个节点的内存地址)。
单双向列表应用的差异主要体现在删除节点上
//完成对当前节点的删除
temp1.pre.next=temp1.next;
//当前节点为尾节点时,不能执行下句,否则会出现空指针异常
if (temp1.next!=null) { temp1.next.pre = temp1.pre;}
1 /** 2 * 根据no删除节点 3 * 双向链表可以实现当前节点的自我删除,不需要通过上一个节点删除 4 */ 5 public void deleteNode(int no){ 6 HeroNode1 temp1=headNode1.next; 7 boolean flag=false; 8 if (temp1==null){ 9 return; 10 } 11 while (true){ 12 if (temp1 == null) { 13 break;//temp节点为尾节点 14 } 15 //如果当前节点为要删除的节点 16 if (no==temp1.no){ 17 flag=true; 18 break; 19 } 20 temp1=temp1.next;//当前节点temp为尾节点时,则有temp=temp.next==null,所以下次循环时会退出循环 21 } 22 if (flag){ 23 //完成对当前节点的删除 24 temp1.pre.next=temp1.next; 25 //当前节点为尾节点时,不能执行下句,否则会出现空指针异常 26 if (temp1.next!=null) { 27 temp1.next.pre = temp1.pre; 28 } 29 30 }else { 31 throw new RuntimeException("该节点不存在"); 32 } 33 }
原文地址:https://www.cnblogs.com/Cong-l/p/12715225.html
- JVM快速入门
- SQL学习之使用常用函数处理数据
- Javascript快速入门(上篇)
- SQL练习之不反复执行相同的计算
- SQL练习之求解填字游戏
- 快速入门系列--WCF--08扩展与新特性
- SQL练习之两个列值的交换
- Parcel,零配置开发 React 应用!
- 像 React Native 开发 APP 一样,用wn-cli 开发 weapp (微信小程序)
- 正则表达式快速入门
- JavaScript之<script>标签简介
- 数控机床数控系统选择4大关键要素
- Python快速入门
- Jquer学习之jQuery(function(){})与(function(){})(jQuery)之间的区别
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Linux系统下Tomcat8启动速度很慢的解决方法
- Linux下查看binlog文件创建时间的命令
- Linux下修改文件权限(所有权)
- Sticks(UVA - 307)【DFS+剪枝】
- Linux CentOS服务器搭建与初始化配置教程
- Centos6.9安装vsftpd并配置多用户的方法
- linux c下log输出代码模板示例代码
- linux adsl 拨号自动配置脚本的方法
- Python调用ip代理案例,快代理api调用demo
- centos7(redhat7)如何卸载自带yum并且安装国内yum源的方法
- linux用户组以及权限总结
- Linux Crontab Shell脚本实现秒级定时任务的方法
- Linux配置SSH和Xshell连接服务器的教程(图解)
- 增强Linux内核中访问控制安全的方法
- 使用Samba在Linux服务器上搭建共享文件服务的方法