/**
-
1.2 在链表中间,根据节点的序号来插入节点,这样的话,上述在链表尾部增加节点可以看成是这种情况的特例
-
@param heroNode 加入的节点
*/
public void addMiddleNode(HeroNode heroNode) {
//flag来判断该节点的序号在链表中是否存在
//要考虑三种情况:
//1 新加入节点的序号在尾节点
//2 新加入的节点的序号在链表中已经存在,所以,要做一个报错处理
//3 新加入的节点的序号在链表中不存在,允许加入
boolean flag = false;
HeroNode tempNode = headNode;
while (true) {
if(tempNode.next==null){
break;
}
if (tempNode.next.no==heroNode.no){
flag=true;
break;
}
else if (tempNode.next.no>heroNode.no){
break;
}
tempNode=tempNode.next;
}
if (flag) {
System.out.println(“该链表中已经存在该序号的节点\n”);
} else {
heroNode.next=tempNode.next;
tempNode.next=heroNode;
}
}
/**
-
2 删。因此tempNode初始定义为headNode,所以,它之后就代表了这条链表
-
很好,没有补位,只是将这个节点删除了。
*/
public void deleteNode(int no){
boolean flag=false;
HeroNode tempNode = headNode;
while(true){
if(tempNode.next==null){
break;
}
if(tempNode.next.no==no){
flag=true;
break;
}
tempNode=tempNode.next;
}
if (flag==true){
//tempNode.next这个节点会被Java的垃圾回收机制自动回收
tempNode.next=tempNode.next.next;
}
else{
System.out.println(“该链表中不存在该节点。\n”);
}
}
/**
-
3 改。改的原则就是四个域中,只需修改name域与nickname域,no不必修改。
-
之前想不明白的就是为什么next域不用改,现在知道了。
*/
public void replaceNode(HeroNode heroNode){
//考虑两种情况:
//1 链表中不存在该序号
//2 链表中存在该序号
boolean flag=false;
HeroNode tempNode = headNode;
//考虑所有可能出现的情况
if(tempNode.next==null){
System.out.println(“该链表为空,无法修改节点。\n”);
//直接跳出方法
return;
}
while(true){
if(tempNode.next.no==heroNode.no){
flag=true;
break;
}
if(tempNode.next==null){
break;
}
tempNode=tempNode.next;
}
if(flag==true){
tempNode.next.name=heroNode.name;
tempNode.next.nickname=heroNode.nickname;
}
else{
System.out.println(“链表中不存在该序号!\n”);
}
}
/**
- 4 查,即遍历输出链表中的全部元素。
*/
public void shownode() {
HeroNode tempNode = headNode;
//对于数组中个数未知的情况,就不适合用for,而是应该用while
while (true) {
if (tempNode == null) {
break;
}
//因为我在HeroNode类中重写了toString方法,所以这里的toString的作用就是控制器print输出对象的全部属性
System.out.println(tempNode);
tempNode = tempNode.next;
}
}
}
/**
- 一个基本类是必不可少的
*/
//为什么这个类前面不能加public →因为文件名必须与 public 的类名保持一致,如果一个文件里面有多个public关键字定义的类,那就会报错
class HeroNode {
public int no;
public String name;
public String nickname;
//我还是想不明白,为什么next可以当成一个,不断指向后一个数。2020/9/3 明天写好这段代码,调试一下。
//调试完我终于知道了,这个类与上述的list类相结合起来时,这个next域起到作用,太妙了。把next当成一个变量。
//我似乎知道了,其实链表的每一个节点存储着两个域,分别是data域和next域,next域用于指向下一个节点 2020/9/4
public HeroNode next;
public HeroNode(int no, String name, String nickname) {
this.no = no;
this.name = name;
this.nickname = nickname;
}
//重写的话尽然还需要专门来一个注释,可怕
//我们可以重写同String()方法来获得(控制器输出)对象的全部属性
@Override
public String toString() {
return “HeroNode[no=” + no + “,name=” + name + “,nickname=” + nickname + “]”;
}
}
[](()3.2 双向链表
[](()3.2.1 概念
为什么要用双向链表呢?因为,单向链表存在以下缺点:
-
单向链表的查找方向只能是一个方向,而双向链表可以向前或者向后查找;
-
单向链表不能自我删除节点,而需要靠辅助节点,而双向链表可以实现自己删除,但是在代码实现中还是需要定义 tempNode 临时结点。
[](()3.2.2 实现原理和应用实例
和单向链表一样,我用水浒传排行榜的增、删、改、查来代码实现双向链表。
在节点类中,唯一与单向链表不同的是,双向链表除了单向链表的域外,还有一个 pre域,用于指向前一个节点。如下图所示:
代码的实现原理见代码中注释,具体步骤和单向链表类似。
[](()3.2.3 代码实现
public class DoubleLinkedListView {
public static void main(String[] args) {
//首先可以先建立一些节点
HeroNode hero1 = new HeroNode(1, “宋江”, “及时雨”);
HeroNode hero2 = new HeroNode(2, “卢俊义”, “玉麒麟”);
HeroNode hero3 = new HeroNode(3, “吴用”, “智多星”);
DoubleLinkedList doublelinkedlist = new DoubleLinkedList();
//增
doublelinkedlist.addTailNode(hero1);
doublelinkedlist.addTailNode(hero3);
//删
doublelinkedlist.deleteNode(3);
//改:只修改name和nickname,不修改其它四个变量
HeroNode hero4=new HeroNode(1,“赵志明”,“sharm”);
doublelinkedlist.replaceNode(hero4);
//查
System.out.println(“显示链表的信息……”);
doublelinkedlist.shownode();
}
}
/**
- 用来存放基本类,这是一种面向对象的编程思想
*/
class DoubleLinkedList {
//首先定义一个头节点:头节点的作用仅仅是表示单链表的头
public HeroNode headNode = new HeroNode(0, “”, “”);
//增、删、改、查
//首先书写增。增有两种情况,一种是在链表末尾增加节点,另一种是在链表中增加节点。
/**