个人简介
😎大家好,我是辉code⬅️⬅️往期文章可以查看我的主页进行观看哦
👊因为坚持才有幸运的机会!!
❤️点赞随意,关注随缘,你的支持是我坚持的动力!
👊此文章的专栏 数据结构
文章目录
前言
跟着B站尚硅谷老韩的数据结构进行学习,所做的笔记。若是对你有用,点赞,关注支持一下!!我会持续更新。此文章是介绍链表的基本知识,单向链表与双向链表基于java语言的实现。
链表
1.介绍
链表是有序的列表,但是它在内存(实际地址)中是存储如下(不连续)
小结:
- 链表是以节点的方式来存储,是链式存储
- 每个节点包含 data 域, next 域:指向下一个节点.
- 如图:发现链表的各个节点不一定是连续存储.
- 链表分带头节点的链表和没有头节点的链表,根据实际的需求来确定
单链表(带头结点) 逻辑结构示意图如下
2.单链表案例
使用带head头的单向链表实现 –水浒英雄排行榜管理完成对英雄人物的增删改查操作
2.1添加
2.1.1 尾部添加
第一种方法在添加英雄时,直接添加到链表的尾部
类:class HeroNode { int no String name; String nickName HeroNode next}
添加(创建)
- 先创建一个head 头节点, 作用就是表示单链表的头
- 后面我们每添加一个节点,就直接加入到 链表的最后temp.next = hero
遍历: - 通过一个辅助变量遍历,帮助遍历整个链表
public void add(HeroNode hero){
HeroNode temp = head;
while (true){
if (temp.next == null){
break;
}
temp = temp.next;
}
//指向最结点
temp.next = hero;
}
2.1.2 有序添加
第二种方式在添加英雄时根据排名将英雄插入到指定位置(如果有这个排名,则添加失败,并给出提示)
需要按照编号的顺序添加
- 首先找到新添加的节点的位置, 是通过辅助变量(指针), 通过遍历来搞定
- 新的节点.next = temp.next
- 将temp.next = 新的节点
//第二种添加方法:将数据按顺序存储
public void addByOrder(HeroNode hero){
boolean flag = false; //用于判断是否可以加入
HeroNode temp = head; //临时变量
//while循环,三个条件可以退出 1.temp.next=null时,2.找到时:temp.next.no > hero.no,3.相同时 temp.next.no ==hero.no
while (true){
if (temp.next == null){
break;
}else if(temp.next.no == hero.no){
flag = true;
break;
}else if (temp.next.no > hero.no){ //找到
break;
}
temp =temp.next;
}
if (flag){
System.out.println("添加值"+hero+"已经存在请勿重复添加");
return;
}
//添加进去 hero.next = temp.next; temp.next=hero;
hero.next =temp.next;
temp.next=hero;
}
2.2修改
思路
- 通过循坏找到改节点
- temp.next.name = newHero.name;
- temp.next.nickName = newHero.nickName;
//修改方法
public void update(HeroNode newHero){
if (head.next == null){
System.out.println("链表为空");
return;
}
//定义一个临时变量,和找到的标志flag,
// 定义while循环,1.没找到 ,2.找到了,
HeroNode temp =head;
boolean flag =false;
while (true){
if (temp.next == null){
System.out.println("没有对应的no值 ");
return;
}else if (temp.next.no == newHero.no){
//找到了
flag = true;
break;
}
temp = temp.next;
}
if (flag){
temp.next.name = newHero.name;
temp.next.nickName = newHero.nickName;
}
}
2.3删除
分析思路
从单链表中删除一个节点的思路
1 . 我们先找到 需要删除的这个节点的前一个节点 temp
2. temp.next = temp.next.next
3. 被删除的节点,将不会有其它引用指向,会被垃圾回收机制回收
//删除方法
public void del(int no){
if (head.next == null){
System.out.println("链表为空");
return;
}
//定义一个临时变量,和找到的标志flag,
// 定义while循环,1.没找到 ,2.找到了,
HeroNode temp =head;
boolean flag =false;
while (true){
if (temp.next == null){
System.out.println("没有对应的no值 ");
return;
}else if (temp.next.no == no){
//找到了
flag = true;
break;
}
temp = temp.next;
}
if (flag){
temp.next = temp.next.next;
}
}
2.4单链表总体代码
/**
* 作者:灰爪哇
* 时间:2022-12-30
*/
//将加入的数据添加到链表最后节点
public class SingleLinkedListDemo {
public static void main(String[] args) {
HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");
HeroNode hero3 = new HeroNode(3, "卢俊义", "玉麒麟");
HeroNode hero2 = new HeroNode(2, "吴用", "智多星");
HeroNode hero4 = new HeroNode(4, "林冲", "豹子头");
HeroNode hero5 = new HeroNode(4, "林冲哥", "豹子头~~~");
SingleLinkedList singleLinkedList = new SingleLinkedList();
// 第一种添加测试
// singleLinkedList.add(hero1);
// singleLinkedList.add(hero3);
// singleLinkedList.add(hero2);
// singleLinkedList.add(hero4);
//第二种添加测试
singleLinkedList.addByOrder(hero1);
singleLinkedList.addByOrder(hero3);
singleLinkedList.addByOrder(hero2);
singleLinkedList.addByOrder(hero4);
singleLinkedList.update(hero5);
singleLinkedList.del(4);
singleLinkedList.del(3);
singleLinkedList.del(2);
singleLinkedList.del(1);
singleLinkedList.list();
}
}
//创建一个链表,一个添加方法,一个展示方法
class SingleLinkedList{
//定义头指针
private HeroNode head = new HeroNode(0,"","");
//添加方法:使用临时变量,这是直接将数据添加到链表最后
public void add(HeroNode hero){
HeroNode temp = head;
while (true){
if (temp.next == null){
break;
}
temp = temp.next;
}
//指向最结点
temp.next = hero;
}
//第二种添加方法:将数据按顺序存储
public void addByOrder(HeroNode hero){
boolean flag = false; //用于判断是否可以加入
HeroNode temp = head; //临时变量
//while循环,三个条件可以退出 1.temp.next=null时,2.找到时:temp.next.no > hero.no,3.相同时 temp.next.no ==hero.no
while (true){
if (temp.next == null){
break;
}else if(temp.next.no == hero.no){
flag = true;
break;
}else if (temp.next.no > hero.no){ //找到
break;
}
temp =temp.next;
}
if (flag){
System.out.println("添加值"+hero+"已经存在请勿重复添加");
return;
}
//添加进去 hero.next = temp.next; temp.next=hero;
hero.next =temp.next;
temp.next=hero;
}
//修改方法
public void update(HeroNode newHero){
if (head.next == null){
System.out.println("链表为空");
return;
}
//定义一个临时变量,和找到的标志flag,
// 定义while循环,1.没找到 ,2.找到了,
HeroNode temp =head;
boolean flag =false;
while (true){
if (temp.next == null){
System.out.println("没有对应的no值 ");
return;
}else if (temp.next.no == newHero.no){
//找到了
flag = true;
break;
}
temp = temp.next;
}
if (flag){
temp.next.name = newHero.name;
temp.next.nickName = newHero.nickName;
}
}
//删除方法
public void del(int no){
if (head.next == null){
System.out.println("链表为空");
return;
}
//定义一个临时变量,和找到的标志flag,
// 定义while循环,1.没找到 ,2.找到了,
HeroNode temp =head;
boolean flag =false;
while (true){
if (temp.next == null){
System.out.println("没有对应的no值 ");
return;
}else if (temp.next.no == no){
//找到了
flag = true;
break;
}
temp = temp.next;
}
if (flag){
temp.next = temp.next.next;
}
}
//展示方法
public void list(){
//判断链表是否为空
if(head.next == null){
System.out.println("链表为空");
return;
}
HeroNode temp = head.next;
while (true){
if (temp == null){
break;
}
System.out.println(temp);
temp = temp.next;
}
}
}
//创建一个英雄类
class HeroNode{
public int no;
public String name;
public String nickName;
public HeroNode next;
HeroNode(int no, String name, String nickName) {
this.no = no;
this.name = name;
this.nickName = nickName;
}
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
", nickName='" + nickName + '\'' +
'}';
}
}
3.双向链表
单向链表的缺点分析:
- 单向链表,查找的方向只能是一个方向,而双向链表可以向前或者向后查找。
- 单向链表不能自我删除,需要靠辅助节点 ,而双向链表,则可以自我删除,前面我们单链表删除时节点,总是需要找到temp,temp是待删除节点的前一个节点.
双向链表示意图
3.1分析双向链表实现思路
分析双向链表的遍历,添加,修改,删除的操作思路===》代码实现
- 遍历 方和 单链表一样,只是可以向前,也可以向后查找
- 添加 (默认添加到双向链表的最后)
(1) 先找到双向链表的最后这个节点
(2) temp.next = newHeroNode
(3) newHeroNode.pre = temp; - 修改 思路和 原来的单向链表一样.
- 删除
(1) 因为是双向链表,因此,我们可以实现自我删除某个节点
(2) 直接找到要删除的这个节点,比如temp
(3) temp.pre.next = temp.next
(4) temp.next.pre = temp.pre;
//删除方法
public void del(int no) {
if (head.next == null) {
System.out.println("链表为空");
return;
}
//定义一个临时变量,和找到的标志flag,
// 定义while循环,1.没找到 ,2.找到了,
HeroNode2 temp = head.next;
boolean flag = false;
while (true) {
if (temp == null) {
System.out.println("没有对应的no值 ");
return;
} else if (temp.no == no) {
//找到了
flag = true;
break;
}
temp = temp.next;
}
if (flag) {
temp.pre.next = temp.next;
if (temp.next != null) {
temp.next.pre = temp.pre;
}
}
}
3. 2双向链表总体代码
/**
* 作者:灰爪哇
* 时间:2022-12-31
*/
public class DoubleLinkedListDemo {
public static void main(String[] args) {
HeroNode2 hero1 = new HeroNode2(1, "宋江", "及时雨");
HeroNode2 hero2 = new HeroNode2(2, "吴用", "智多星");
HeroNode2 hero3 = new HeroNode2(3, "卢俊义", "玉麒麟");
HeroNode2 hero4 = new HeroNode2(4, "林冲", "豹子头");
// HeroNode hero5 = new HeroNode(4, "林冲哥", "豹子头~~~");
DoubleLinkedList doubleLinkedList = new DoubleLinkedList();
doubleLinkedList.add(hero1);
doubleLinkedList.add(hero2);
doubleLinkedList.add(hero3);
doubleLinkedList.add(hero4);
doubleLinkedList.list();
System.out.println("--------");
//修改方法测试
HeroNode2 hero5 = new HeroNode2(4, "林冲哥", "豹子头~~~");
doubleLinkedList.update(hero5);
doubleLinkedList.list();
System.out.println("-------------");
//删除方法测试
doubleLinkedList.del(4);
doubleLinkedList.list();
}
}
//创建一个链表,一个添加方法,一个展示方法
class DoubleLinkedList {
//定义头指针
private HeroNode2 head = new HeroNode2(0, "", "");
//添加方法:使用临时变量,这是直接将数据添加到链表最后
public HeroNode2 getHead() {
return head;
}
//添加方法
public void add(HeroNode2 hero) {
HeroNode2 temp = head;
while (true) {
if (temp.next == null) {
break;
}
temp = temp.next;
}
//指向最结点
temp.next = hero;
hero.pre = temp;
}
//修改方法 ,跟单链表基本一样,因为他没有改变指针指向
public void update(HeroNode2 newHero) {
if (head.next == null) {
System.out.println("链表为空");
return;
}
//定义一个临时变量,和找到的标志flag,
// 定义while循环,1.没找到 ,2.找到了,
HeroNode2 temp = head;
boolean flag = false;
while (true) {
if (temp.next == null) {
System.out.println("没有对应的no值 ");
return;
} else if (temp.next.no == newHero.no) {
//找到了
flag = true;
break;
}
temp = temp.next;
}
if (flag) {
temp.next.name = newHero.name;
temp.next.nickName = newHero.nickName;
}
}
//删除方法
public void del(int no) {
if (head.next == null) {
System.out.println("链表为空");
return;
}
//定义一个临时变量,和找到的标志flag,
// 定义while循环,1.没找到 ,2.找到了,
HeroNode2 temp = head.next;
boolean flag = false;
while (true) {
if (temp == null) {
System.out.println("没有对应的no值 ");
return;
} else if (temp.no == no) {
//找到了
flag = true;
break;
}
temp = temp.next;
}
if (flag) {
temp.pre.next = temp.next;
if (temp.next != null) {
temp.next.pre = temp.pre;
}
}
}
//展示方法
public void list() {
//判断链表是否为空
if (head.next == null) {
System.out.println("链表为空");
return;
}
HeroNode2 temp = head.next;
while (true) {
if (temp == null) {
break;
}
System.out.println(temp);
temp = temp.next;
}
}
}
//创建一个英雄类
class HeroNode2{
public int no;
public String name;
public String nickName;
public HeroNode2 next;
public HeroNode2 pre;
HeroNode2(int no, String name, String nickName) {
this.no = no;
this.name = name;
this.nickName = nickName;
}
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
", nickName='" + nickName + '\'' +
'}';
}
}
3.3第二种添加方法方法
双向链表的第二种添加方式,按照编号顺序 [示意图]
按照单链表的顺序添加,稍作修改即可.
//第二种添加方法:将数据按顺序存储
public void addByOrder(HeroNode2 hero){
boolean flag = false; //用于判断是否可以加入
HeroNode2 temp = head; //临时变量
//while循环,三个条件可以退出 1.temp.next=null时,2.找到时:temp.next.no > hero.no,3.相同时 temp.next.no ==hero.no
while (true){
if (temp.next == null){
hero.pre = temp;
temp.next =hero;
return;
}else if(temp.next.no == hero.no){
flag = true;
break;
}else if (temp.next.no > hero.no){ //找到
break;
}
temp =temp.next;
}
if (flag){
System.out.println("添加值"+hero+"已经存在请勿重复添加");
return;
}
//添加进去 hero.next = temp.next; temp.next=hero;
temp.next.pre = hero;
hero.pre = temp;
hero.next = temp.next;
temp.next = hero;
}
总结
若是有所收获,点赞,关注支持一下!!谢谢!!❤️❤️❤️❤️❤️