链表(LinkedList)
链表是有序的列表,但是其在内存的存储不一定连续
由这张图我们可以看出
-
链表是以节点的方式来存储的,是链式存储
-
每个节点包含data域,next域:指向下一个节点
-
我们可以发现链表的各个节点不一定是连续存储的
-
链表分为带头节点的链表和没有头节点的链表
单链表创建思路分析
-
先创建一个head头节点,作用就是表示单链表的头
-
然后我们每添加一个节点,就直接加入到链表的最后
遍历
我们可以声明一个变量,让他帮助我们遍历完该链表
代码实现
//定义HeroNode,每个HeroNode对象就是一个节点
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 + '\'' +
'}';
}
}
实现我们的链表
// 定义SingleLinkedList管理我们的英雄
class SingleLinkedList {
// 先初始化一个头节点,头节点不要动
private HeroNode head = new HeroNode(0, "", "");
/* 添加节点到单向链表
思路:当不考虑编号顺序时
1. 找到当前链表的最后一个节点
2.将最后的这个节点的next指向新的节点*/
public void add(HeroNode heroNode) {
// 因为head节点不能动 所以我们要声明一个变量帮助遍历
HeroNode cur = head;
// 遍历链表 找到最后
while (true) {
// 找到链表的最后
if (cur.next == null) {
break;
}
// 如果没有找到最后,将cur后移
cur = cur.next;
}
// 当退出while循环时,cur指向最后
cur.next = heroNode;
}
// 显示链表[遍历]
public void show() {
// 判断链表是否为空
if (head.next == null) {
System.out.println("链表为空");
return;
}
HeroNode cur = head.next;
while (true) {
if (cur == null) {
break;
}
// 输出节点信息
System.out.println(cur);
// 将cur后移,否则会出现死循环
cur = cur.next;
}
}
}
对以上方法进行测试
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.add(hero1);
singleLinkedList.add(hero2);
singleLinkedList.add(hero3);
singleLinkedList.add(hero4);
singleLinkedList.show();
}
这里如果我们改变添加的顺序,我们会发现,输出的结果是按照我们添加的顺序显现出来的而不是按照编号的顺序显现的
按照编号的顺序添加(链表的插入)
思路:
-
首先找到新添加的节点的位置,是通过辅助变量,通过遍历来搞定的
-
新的节点.next=temp.next
-
将temp.next=新的节点s
代码实现
/*
* 第二种方式在添加英雄时,根据排名将英雄插入到指定位置
* (如果这个排名已经存在了,则添加失败,并给出提示)
* */
public void insert(HeroNode heroNode){
// 头节点不能动,需要辅助变量
// 因为单链表,我们找到的temp是位于添加位置的前一个节点,否则插入不了
HeroNode temp = head;
boolean flag = false;// flag标志添加的编号已经存在 无法添加
while (true){
if (temp.next==null){// 说明temp已经在链表的最后了
break;
}
if (temp.next.no>heroNode.no){// 说明已经找到了要插入的位置,就在temp后面插入
break;
}else if (temp.next.no==heroNode.no){// 说明需要添加的节点点已经存在了
flag=true;// 说明编号存在
break;
}
temp=temp.next;
}
if (flag){
System.out.println("编号已经存在 不能加入:"+heroNode.no);
}else {
// 插入到链表,temp的后面
heroNode.next=temp.next;
temp.next=heroNode;
}
}
对以上代码的测试
singleLinkedList.insert(hero1);
singleLinkedList.insert(hero4);
singleLinkedList.insert(hero3);
singleLinkedList.insert(hero2);
singleLinkedList.show();
这样写出的代码,最终经过我们的测试,其是按照我们的编号进行升序排列的,也就是实现了我们链表的插入
ps: heroNode.next=temp.next; temp.next=heroNode;
这两处的代码顺序一定不能改变,否则就形成了一个死循环,具体我们可以通过debug来发现这个问题