本篇博客是根据b站尚硅谷老师的数据结构教程,学习后写的学习笔记 部分概念和图片均来自视频,代码和截图均为自己动手,本篇博客的重点在自己编写的代码注释上 尚硅谷Java数据结构与java算法(Java数据结构与算法)
单链表
链表是有序的列表(Linked List),在内存中的存储方式如上图所示
(1)链表是以节点的方式来存储,是链式存储
(2)每个节点包含data域,next域。其中,data域用来保存当前节点要存储的数据,next域用来指向下一个节点
(3)链表的各个节点不一定是连续存储
(4)链表分为带头节点的链表和没有头节点的链表,根据实际的需求来确定
单链表(带头节点)逻辑结构示意图如下 这里看起来像是顺序连续存储,但实际上不是,下一个节点是什么,由next域来决定
单链表完整代码
节点类,用来创建一个新节点
class HeroNode{
public int no;
public String name;
public String nickname;
public HeroNode next;
public 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 + '\'' +
'}';
}
}
创建单链表
class SingleLinkedList{
private HeroNode head = new HeroNode(0,"","");
}
一个完整的单链表应该可以实现节点的增删改查,所以 接下来就是往这个单链表类里面加上添加节点,删除节点,修改节点,遍历输出等方法
将新节点添加到单链表尾部
public void add(HeroNode heroNode){
HeroNode temp = head;
while(true){
if(temp.next == null){
break;
}
temp = temp.next;
}
temp.next = heroNode;
}
将新节点按照编号插入到指定位置
public void addByNo(HeroNode heroNode){
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;
}
temp = temp.next;
}
if(flag){
System.out.printf("准备插入的编号 %d 已经存在,插入失败\n",heroNode.no);
} else {
heroNode.next = temp.next;
temp.next = heroNode;
}
}
修改节点
public void update(HeroNode newHeroNode){
if(head.next == null){
System.out.println("链表为空");
}
HeroNode temp = head.next;
boolean flag = false;
while(true){
if(temp == null){
break;
}
if(temp.no == newHeroNode.no){
flag = true;
break;
}
temp = temp.next;
}
if(flag){
temp.name = newHeroNode.name;
temp.nickname = newHeroNode.nickname;
}else{
System.out.printf("需要修改的编号为 %d 的节点不存在\n",newHeroNode.no);
}
}
删除节点
public void del(int no){
HeroNode temp = head;
boolean flag = false;
while(true){
if(temp.next == null){
break;
}
if(temp.next.no == no){
flag = true;
break;
}
temp = temp.next;
}
if(flag){
temp.next = temp.next.next;
}else{
System.out.printf("需要删除的编号为 %d 的节点不存在\n",no);
}
}
显示全部节点
public void list(){
if(head.next == null){
System.out.println("链表为空");
}
HeroNode temp = head.next;
while(true){
if(temp==null){
break;
}
System.out.println(temp);
temp = temp.next;
}
}
main函数
public static void main(String[] args) {
HeroNode hero1 = new HeroNode(1,"宋江","及时雨");
HeroNode hero2 = new HeroNode(2,"卢俊义","玉麒麟");
HeroNode hero3 = new HeroNode(3,"吴用","智多星");
HeroNode hero4 = new HeroNode(4,"林冲","豹子头");
SingleLinkedList singleLinkedList = new SingleLinkedList();
singleLinkedList.addByNo(hero1);
singleLinkedList.addByNo(hero3);
singleLinkedList.addByNo(hero4);
singleLinkedList.addByNo(hero2);
HeroNode newHeroNode = new HeroNode(2,"卢","玉");
singleLinkedList.update(newHeroNode);
singleLinkedList.del(4);
singleLinkedList.list();
}
最终结果为
双向链表
双向链表与单向链表不同,单向链表每个节点只有一个next用来指向下一个节点,而双向链表每个节点有一个pre用来指向上一个节点,有一个next用来指向下一个节点。 图片来源:http://c.biancheng.net/view/3342.html
双向链表代码
创建节点
class HeroNode2{
public int no;
public String name;
public String nickname;
public HeroNode2 next;
public HeroNode2 pre;
public 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 + '\'' +
'}';
}
}
创建一个双向链表
class DoubleLinkedList{
HeroNode2 head = new HeroNode2(0,"","");
public HeroNode2 getHead(){
return head;
}
}
将新节点插入到双向链表的最后面
public void add(HeroNode2 heroNode){
HeroNode2 temp = head;
while(true){
if(temp.next == null){
break;
}
temp = temp.next;
}
temp.next = heroNode;
heroNode.pre = temp;
}
按照编号将新节点插入到指定位置
public void addByNo(HeroNode2 heroNode){
HeroNode2 temp = head;
boolean flag1 = false;
boolean flag2 = false;
while(true){
if(temp.next == null){
flag2 = true;
break;
}
if(temp.next.no > heroNode.no){
break;
}
if(temp.next.no == heroNode.no){
flag1 = true;
break;
}
temp = temp.next;
}
if(flag1){
System.out.println("节点的no重复,插入失败");
}else{
if(!flag2){
temp.next.pre = heroNode;
heroNode.next = temp.next;
}
heroNode.pre = temp;
temp.next = heroNode;
}
}
修改节点
public void update(HeroNode2 newHeroNode){
if(head.next == null){
System.out.println("链表为空");
}
HeroNode2 temp = head.next;
boolean flag = false;
while(true){
if(temp == null){
break;
}
if(temp.no == newHeroNode.no){
flag = true;
break;
}
temp = temp.next;
}
if(flag){
temp.name = newHeroNode.name;
temp.nickname = newHeroNode.nickname;
}else{
System.out.printf("需要修改的编号为 %d 的节点不存在\n",newHeroNode.no);
}
}
删除节点
public void del(int no){
if(head.next == null){
System.out.println("当前链表为空,无法删除");
}
HeroNode2 temp = head.next;
boolean flag = false;
while(true){
if(temp == null){
break;
}
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;
}
}else{
System.out.printf("需要删除的编号为 %d 的节点不存在\n",no);
}
}
显示全部节点
public void list(){
if(head.next == null){
System.out.println("链表为空");
}
HeroNode2 temp = head.next;
while(true){
if(temp==null){
break;
}
System.out.println(temp);
temp = temp.next;
}
}
main函数
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,"林冲","豹子头");
DoubleLinkedList doubleLinkedList = new DoubleLinkedList();
doubleLinkedList.addByNo(hero1);
doubleLinkedList.addByNo(hero4);
doubleLinkedList.addByNo(hero2);
doubleLinkedList.addByNo(hero3);
doubleLinkedList.list();
}
虽然插入顺序不同,但最终双向链表中节点是按照编号no的顺序从小到大排列的
加上修改和删除语句
HeroNode2 newHeroNode = new HeroNode2(4,"零充","没钱");
doubleLinkedList.update(newHeroNode);
doubleLinkedList.del(1);
doubleLinkedList.list();
|