1. 应用场景
- 当不知道数据量大小的时候,可以使用“链表”来动态储存和处理数据
2. 思路
- 分类:(本文使用 “有头节点”)
- 有头节点 链表
- 无头节点 链表
- 存储方式:节点
- 节点结构:
- 数据域(Data):存储 当前节点 的 数据
- 地址域(Next):指向 下一个节点 的 地址
- 头指针:数据域无意义,只有指向下一节点的地址域
- 不一定 是连续存储
- 数值按照顺序(本文章按照从小到大顺序)
3. 数据结构(类结构):
【节点 Node】
(1)成员变量(Field)
- data: int,节点所储存的数据
- nextNode: Node,所指向的下一个节点
private int data;
private Node nextNode;
(2)初始化 / 构造器(Constructor)
- 参数传入节点所要储存的数据
- 初始化节点数据
public Node(int data) {
this.data = data;
}
(3)方法(Methods)
- 两个成员变量的getter和setter
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public Node getNextNode() {
return nextNode;
}
public void setNextNode(Node nextNode) {
this.nextNode = nextNode;
}
- toString方法
@Override
public String toString() {
return "Node{" +
"data=" + data +
'}';
}
【有序单链表 OrderedSingleLinkedList】
(1)成员变量(Field)
- headPointer: Node,头节点,不储存数据,只通过自身的nextNode负责储存第一个Node的地址。当有序单链表创建时直接实例化,数据域为0。
private Node headPointer = new Node(0);
(2)初始化 / 构造器(Constructor)
- 默认构造器
(3)方法(Methods)
- 添加新节点
addNode(Node) -> void
- 将头指针赋值到一个临时变量,此临时变量用来储存循环遍历时的当前节点。
- 通过循环遍历寻找 要插入的位置
- 循环过程中,如果 当前节点的下一节点 为 null,说明到达链表末尾,结束循环,准备将新节点插入当前节点的下一节点位置。
- 循环过程中,如果当前节点的 下一节点的值大于新节点的值,说明找到需要插入的位置。结束循环,准备将新节点插入当前节点的下一节点位置。
- 循环过程中,如果上述两条均不符合,则将当前节点的 下一节点赋值给当前节点变量,继续循环。
- 循环结束后,将新节点插入到 当前节点和当前节点的下一节点之间
public void addNode(Node newNodePractice) {
// 1. 头指针赋值到临时变量
Node currentNode = this.headPointer;
// 2. 进行循环遍历,寻找新节点应当插入的位置,并插入新节点
while (true) {
// (1) 若next节点为null 或 new节点值小于next节点值,说明找到插入点,结束循环
if (currentNode.getNextNode() == null || newNodePractice.getData() < currentNode.getNextNode().getData()) {
break;
}
// (2) 若new节点值等于next节点值,抛出异常;否则new节点值大于next节点值,将next节点赋值给temp节点
if (newNodePractice.getData() == currentNode.getNextNode().getData()) {
throw new RuntimeException("There is a data equals to the new data");
}
currentNode = currentNode.getNextNode();
}
// 3. 将new节点插入到current节点和next节点之间
Node tempNode = currentNode.getNextNode();
currentNode.setNextNode(newNodePractice);
newNodePractice.setNextNode(tempNode);
}
- 查找某节点是否存在
isNodeExist(Node) -> boolean
- 先判断链表是否为空
- 设置一个 boolean变量 ,用来标识 是否找到了该节点,默认值为false
- 将头指针赋值到一个临时变量,此临时变量用来储存循环遍历时的当前节点。
- 通过循环遍历寻找 是否存在一个节点与输入节点有相同值的节点
- 若 当前节点的下一节点 为null,说明到达链表末尾,退出循环
- 若输入节点值等于下一节点值,找到相同节点,设置found为true,退出循环
- 若上述条件 均不满足,将下一节点赋值给当前节点变量,继续循环
- 结束循环后,返回 boolean变量
public boolean isNodeExist(Node inputNodePractice) {
// 1. 判断链表是否为空,是则抛出异常
if (this.headPointer.getNextNode() == null) {
throw new RuntimeException("The single linked list is empty!");
}
// 2. 设置boolean来判断是否找到存在的相同值,初始值为false
boolean found = false;
// 3. 头指针赋值到临时变量
Node currentNode = this.headPointer;
// 4. 进行循环遍历,寻找输入节点的相同节点
while (true) {
// (1) 若next节点为null,说明到达链表末尾,退出循环
if (currentNode.getNextNode() == null) {
break;
}
// (2) 若输入节点值等于next节点值,找到相同节点,设置found为true,退出循环
if (inputNodePractice.getData() == currentNode.getNextNode().getData()) {
found = true;
}
// (3) 若上述条件均不满足,将next节点赋值给current节点,继续循环
currentNode = currentNode.getNextNode();
}
// 5.返回isExist
return found;
}
- 删除某节点
deleteNode(Node) -> void
- 判断链表是否为空,是则抛出异常
- 设置boolean变量用来标识是否找到节点,默认值为false
- 设置临时节点变量,赋值为头节点
- 进行循环遍历,寻找 待删除节点的相同节点
- 若 当前节点的下一节点 为null,说明到达链表末尾,退出循环
- 若待删除节点值 等于 下一节点值,找到相同节点,设置found为true,退出循环
- 若上述条件 均不满足,将下一节点赋值给当前节点,继续循环
- 判断 是否找到待删除节点
- 若找到,设置下一节点为 “下一节点的下一节点”,即删除所找到的节点
- 若未找到,抛出异常
public void deleteNode(Node nodePractice) {
// 1. 判断链表是否为空,是则抛出异常
if (this.headPointer.getNextNode() == null) {
throw new RuntimeException("The single linked list is empty!");
}
// 2. 设置boolean用来标识是否找到节点
boolean found = false;
// 3. 设置临时变量,赋值为头节点
Node currentNode = this.headPointer;
// 4. 进行循环遍历,寻找待删除节点的相同节点
while (true) {
// (1) 若next节点为null,说明到达链表末尾,退出循环
if (currentNode.getNextNode() == null) {
break;
}
// (2) 若待删除节点值等于next节点值,找到相同节点,设置found为true,退出循环
if (nodePractice.getData() == currentNode.getNextNode().getData()) {
found = true;
break;
}
// (3) 若上述条件均不满足,将next节点赋值给current节点,继续循环
currentNode = currentNode.getNextNode();
}
// 5. 判断是否找到待删除节点
if (found) {
// (1) 若找到,设置next节点为"next节点的next节点",即删除所找到的节点
currentNode.setNextNode(currentNode.getNextNode().getNextNode());
} else {
// (2) 若未找到,抛出异常
throw new RuntimeException("The node is not found!");
}
}
- 获取全部节点的计数
countNodes() -> int
- 设置int值用来计数
- 设置临时节点变量,赋值为头节点
- 进行循环遍历,每找到一个 非null的节点 count加1
- 若 当前节点的下一节点 为null,退出循环
- 否则 count 加 1,并将下一节点赋值给当前节点,继续循环
- 结束循环后,返回count值
public int countNodes() {
// 1. 设置int值用来计数
int count = 0;
// 2. 设置临时变量,赋值为头节点
Node currentNode = this.headPointer;
// 3. 进行循环遍历,每找到一个非null的节点count加1
while (true) {
if (currentNode.getNextNode() == null) {
break;
}
count++;
currentNode = currentNode.getNextNode();
}
// 4. 返回count
return count;
}
- 打印全部节点的数据
displayAllNodes() -> void
- 判断链表 是否为空,打印"链表为空"
- 设置临时节点变量,赋值为头节点
- 从头节点开始遍历,并打印
- 若 当前节点 为null,退出循环
- 否则 打印 当前节点的数据,并将下一节点赋值给当前节点,继续循环
public void displayAllNodes() {
// 1. 判断链表是否为空,打印"链表为空"
if (this.headPointer.getNextNode() == null) {
System.out.println("The single linked list is empty!");
}
// 2. 头指针的next赋值到临时变量
Node tempNode = this.headPointer.getNextNode();
// 3. 从头节点开始遍历,并打印, 若当前临时节点为null,退出循环
int count = 0;
while (tempNode != null) {
// (1) 若当前节点不为null,打印当前节点的数据
System.out.println(tempNode.toString());
count++;
// (2)将next节点赋值给当前临时节点并,继续循环
tempNode = tempNode.getNextNode();
}
System.out.println("[node count] --> " + count);
}
4. 完整实现
public class OrderedSingleLinkedList {
private Node headPointer = new Node(0);
public void addNode(Node newNodePractice) {
// 1. 头指针赋值到临时变量
Node currentNode = this.headPointer;
// 2. 进行循环遍历,寻找新节点应当插入的位置,并插入新节点
while (true) {
// (1) 若next节点为null 或 new节点值小于next节点值,说明找到插入点,结束循环
if (currentNode.getNextNode() == null || newNodePractice.getData() < currentNode.getNextNode().getData()) {
break;
}
// (2) 若new节点值等于next节点值,抛出异常;否则new节点值大于next节点值,将next节点赋值给temp节点
if (newNodePractice.getData() == currentNode.getNextNode().getData()) {
throw new RuntimeException("There is a data equals to the new data");
}
currentNode = currentNode.getNextNode();
}
// 3. 将new节点插入到current节点和next节点之间
Node tempNode = currentNode.getNextNode();
currentNode.setNextNode(newNodePractice);
newNodePractice.setNextNode(tempNode);
}
public boolean isNodeExist(Node inputNodePractice) {
// 1. 判断链表是否为空,是则抛出异常
if (this.headPointer.getNextNode() == null) {
throw new RuntimeException("The single linked list is empty!");
}
// 2. 设置boolean来判断是否找到存在的相同值,初始值为false
boolean found = false;
// 3. 头指针赋值到临时变量
Node currentNode = this.headPointer;
// 4. 进行循环遍历,寻找输入节点的相同节点
while (true) {
// (1) 若next节点为null,说明到达链表末尾,退出循环
if (currentNode.getNextNode() == null) {
break;
}
// (2) 若输入节点值等于next节点值,找到相同节点,设置found为true,退出循环
if (inputNodePractice.getData() == currentNode.getNextNode().getData()) {
found = true;
}
// (3) 若上述条件均不满足,将next节点赋值给current节点,继续循环
currentNode = currentNode.getNextNode();
}
// 5.返回isExist
return found;
}
public void deleteNode(Node nodePractice) {
// 1. 判断链表是否为空,是则抛出异常
if (this.headPointer.getNextNode() == null) {
throw new RuntimeException("The single linked list is empty!");
}
// 2. 设置boolean用来标识是否找到节点
boolean found = false;
// 3. 设置临时变量,赋值为头节点
Node currentNode = this.headPointer;
// 4. 进行循环遍历,寻找待删除节点的相同节点
while (true) {
// (1) 若next节点为null,说明到达链表末尾,退出循环
if (currentNode.getNextNode() == null) {
break;
}
// (2) 若待删除节点值等于next节点值,找到相同节点,设置found为true,退出循环
if (nodePractice.getData() == currentNode.getNextNode().getData()) {
found = true;
break;
}
// (3) 若上述条件均不满足,将next节点赋值给current节点,继续循环
currentNode = currentNode.getNextNode();
}
// 5. 判断是否找到待删除节点
if (found) {
// (1) 若找到,设置next节点为"next节点的next节点",即删除所找到的节点
currentNode.setNextNode(currentNode.getNextNode().getNextNode());
} else {
// (2) 若未找到,抛出异常
throw new RuntimeException("The node is not found!");
}
}
public int countNodes() {
// 1. 设置int值用来计数
int count = 0;
// 2. 设置临时变量,赋值为头节点
Node currentNode = this.headPointer;
// 3. 进行循环遍历,每找到一个非null的节点count加1
while (currentNode.getNextNode() != null) {
count++;
currentNode = currentNode.getNextNode();
}
// 4. 返回count
return count;
}
public void displayAllNodes() {
// 1. 判断链表是否为空,打印"链表为空"
if (this.headPointer.getNextNode() == null) {
System.out.println("The single linked list is empty!");
}
// 2. 头指针的next赋值到临时变量
Node tempNode = this.headPointer.getNextNode();
// 3. 从头节点开始遍历,并打印, 若当前临时节点为null,退出循环
int count = 0;
while (tempNode != null) {
// (1) 若当前节点不为null,打印当前节点的数据
System.out.println(tempNode.toString());
count++;
// (2)将next节点赋值给当前临时节点并,继续循环
tempNode = tempNode.getNextNode();
}
System.out.println("[node count] --> " + count);
}
}
class Node {
private int data;
private Node nextNode;
public Node(int data) {
this.data = data;
}
@Override
public String toString() {
return "Node{" +
"data=" + data +
'}';
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public Node getNextNode() {
return nextNode;
}
public void setNextNode(Node nextNode) {
this.nextNode = nextNode;
}
}