【数据结构与算法】链表1:单向链表(Java实现)
前言
链表是重要的数据结构之一,这里主要使用Java来实现单向链表中的各项基本功能,以达到学习单向链表的目的。
程序代码
为了实现单向链表,这里主要使用到了下面的三个类:
- Node类:用来定义数据节点
- SingleLinkList类:单向链表类
- TestSingleLinkList类:用来测试单向链表的功能
Node类
程序代码如下:
package chapter03_SingleLinkList;
/*
* 单向链接的节点类型
* 该节点用来保存学生的成绩信息:
* number:学号
* name:姓名
* score:成绩
* next:下一个学生的成绩信息
* 其中,number是唯一的,不允许重复
*/
public class Node {
String number;
String name;
Double score;
Node next;
public Node(String number, String name, Double score){
this.number = number;
this.name = name;
this.score = score;
}
}
SingleLinkList类
程序代码如下:
package chapter03_SingleLinkList;
/*
* 单向链表
* 主要用来保存单向链表的列表首,即提供链表的入口,否则将无法对链表进行操作
* 同时提供一些单向链表的操作方法:
* public boolean isEmpty()
* public boolean isExist(Node node)
* public void displayLinkList()
* public boolean insertNode(Node node)
* public boolean insertNode(Node sourceNode, Node node)
* public boolean deleteNode(Node node)
*
*/
public class SingleLinkList {
public Node firstNode; //链表的第一个节点
public Node lastNode; //链表的最后一个节点
/*
* 判断当前的链表是否为空
*/
public boolean isEmpty(){
return firstNode == null;
}
/*
* 判断节点是否存在(以学号作为唯一标识)
*/
public boolean isExist(Node node){
//如果链表为空,直接返回fasle
if(this.isEmpty())
return false;
Node currentNode = firstNode;
while (currentNode != null) {
if(currentNode.number == node.number)
return true;
currentNode = currentNode.next;
}
//如果上面循环没有执行return语句,说明不存在,返回false
return false;
}
/*
* 输出链表的内容
*/
public void displayLinkList(){
Node currentNode = firstNode;
while (currentNode != null) {
System.out.println("学号:" + currentNode.number + " 姓名:" + currentNode.name + " 成绩:" + currentNode.score);
currentNode = currentNode.next;
}
}
/*
* 向链表中插入节点(默认为在链表最后插入节点)
*/
public boolean insertNode(Node node){
//如果节点已经存在,插入节点失败
if(this.isExist(node)){
System.err.println("节点已经存在,插入节点失败!");
return false;
} else {
//节点不存在时才做插入节点的操作
if(this.isEmpty()){
//如果当前链表为空,则第一个节点和最后一个节点都为当前节点
firstNode = node;
lastNode = node;
} else {
//如果当前链表不为空,设置链表最后一个节点的下一个节点为node
//同时最后一个节点设置为node,从而完成节点的插入操作
lastNode.next = node;
lastNode = node;
}
return true;
}
}
/*
* 向链表中插入节点(在链表某个节点位置插入节点)
*/
public boolean insertNode(Node sourceNode, Node node){
//如果节点已经存在或者sourceNode不存在,插入节点失败
if(this.isExist(node) == true || this.isExist(sourceNode) == false){
System.err.println("节点已经存在或需要插入的节点位置不存在,插入节点失败!");
return false;
} else {
//节点不存在时才做插入节点的操作
if(this.isEmpty()){
//如果当前链表为空,则第一个节点和最后一个节点都为当前节点
firstNode = node;
lastNode = node;
} else {
if(sourceNode.number == firstNode.number){
//如果在开头插入节点
node.next = firstNode;
firstNode = node;
} else if (sourceNode.number == lastNode.number) {
//如果在结尾插入节点
lastNode.next = node;
lastNode = node;
} else {
//如果在中间插入节点
//currentNode--nextNode--nextNextNode
//==>currentNode--node--nextNode--nextNextNode
Node currentNode = firstNode;
Node nextNode = firstNode.next;
while(nextNode.number != sourceNode.number){
currentNode = nextNode;
nextNode = nextNode.next;
}
currentNode.next = node;
node.next = nextNode;
}
}
return true;
}
}
/*
* 删除链表中的节点
*/
public boolean deleteNode(Node node){
//如果节点不存在,删除节点失败
if(this.isExist(node) == false){
System.err.println("节点不存在,删除节点失败!");
return false;
}
if(node.number == firstNode.number){
//如果删除的是第一个节点
firstNode = firstNode.next;
} else if (node.number == lastNode.number) {
//如果删除的是最后一个节点
Node currentNode = firstNode;
while(currentNode.next != lastNode){
currentNode = currentNode.next;
}
currentNode.next = null;
lastNode = currentNode;
} else {
//如果删除的是中间节点
//currentNode--nextNode--nextNextNode
//==>currentNode--nextNextNode
Node currentNode = firstNode;
Node nextNode = firstNode.next;
while(nextNode.number != node.number){
currentNode = nextNode;
nextNode = nextNode.next;
}
currentNode.next = nextNode.next;
}
node.next = null;
return true;
}
}
TestSingleLinkList类
基本程序代码如下:
package chapter03_SingleLinkList;
/*
* 单向链表测试
*/
public class TestSingleLinkList {
public static void main(String[] args) throws InterruptedException {
SingleLinkList singleLinkList = new SingleLinkList();
Node node1 = new Node("3114006441", "叶泳豪", (double) 95);
Node node2 = new Node("3214006442", "陈琳", 90.0);
Node node3 = new Node("3214006443", "李洁玲", 90.0);
Node node4 = new Node("3214006444", "刘映彤", 90.0);
Node node5 = new Node("3214006445", "陈舒敏", 90.0);
Node node6 = new Node("3214006446", "孔冰艳", 90.0);
Node node7 = new Node("3214006447", "余瑞虹", 90.0);
Node node8 = new Node("3214006448", "周桑霓", 90.0);
Node node9 = new Node("3214006449", "何嘉颖", 90.0);
singleLinkList.insertNode(node1);
singleLinkList.insertNode(node2);
singleLinkList.insertNode(node3);
singleLinkList.insertNode(node4);
singleLinkList.insertNode(node5);
singleLinkList.insertNode(node6);
singleLinkList.insertNode(node7);
singleLinkList.insertNode(node8);
singleLinkList.insertNode(node9);
System.out.println("原始链表:");
singleLinkList.displayLinkList();
}
}
可以看到上面的代码只是向链表中添加了部分节点,因为在简单测试的情况下,可以自行修改代码来进行节点的各项内容测试。
测试
插入节点
直接利用上面提供的代码,执行结果如下:
原始链表:
学号:3114006441 姓名:叶泳豪 成绩:95.0
学号:3214006442 姓名:陈琳 成绩:90.0
学号:3214006443 姓名:李洁玲 成绩:90.0
学号:3214006444 姓名:刘映彤 成绩:90.0
学号:3214006445 姓名:陈舒敏 成绩:90.0
学号:3214006446 姓名:孔冰艳 成绩:90.0
学号:3214006447 姓名:余瑞虹 成绩:90.0
学号:3214006448 姓名:周桑霓 成绩:90.0
学号:3214006449 姓名:何嘉颖 成绩:90.0
至于在开头、结尾和中间插入节点的功能,可自行测试。
删除节点
在上面的基础上,添加如下代码:
//分别删除首节点、尾节点和中间节点
singleLinkList.deleteNode(node1);
singleLinkList.deleteNode(node9);
singleLinkList.deleteNode(node5);
//输出删除节点后的链表
System.out.println();
System.out.println("删除节点后的链表:");
singleLinkList.displayLinkList();
执行结果如下:
原始链表:
学号:3114006441 姓名:叶泳豪 成绩:95.0
学号:3214006442 姓名:陈琳 成绩:90.0
学号:3214006443 姓名:李洁玲 成绩:90.0
学号:3214006444 姓名:刘映彤 成绩:90.0
学号:3214006445 姓名:陈舒敏 成绩:90.0
学号:3214006446 姓名:孔冰艳 成绩:90.0
学号:3214006447 姓名:余瑞虹 成绩:90.0
学号:3214006448 姓名:周桑霓 成绩:90.0
学号:3214006449 姓名:何嘉颖 成绩:90.0
删除节点后的链表:
学号:3214006442 姓名:陈琳 成绩:90.0
学号:3214006443 姓名:李洁玲 成绩:90.0
学号:3214006444 姓名:刘映彤 成绩:90.0
学号:3214006446 姓名:孔冰艳 成绩:90.0
学号:3214006447 姓名:余瑞虹 成绩:90.0
学号:3214006448 姓名:周桑霓 成绩:90.0