Hello,小伙伴们大家好,我是才辰,首先祝大家国庆假期快乐!
这次会为大家带来链表的专题的讲解,这篇文章是专题系列的第一篇,分享一下最基础最常用的单链表。
单向链表是链表中最常用的一种,一个列表节点有两个字段,即数据域和指针域。在单向链表中,指向第一个节点的节点称为“头结点”,最后一个节点的指针域设为null。
例如:列表A={1,3,1,4,5,2,1}的单向链表数据结构如下:
在Java语言中,声明一个Node节点类的代码如下:
class Node{
int data;
Node next;
//构造函数
public Node(int data1){
data=data1;
next=null;
}
}
为方便大家查看,我为下面的内容做了一个目录。
- 建立单向链表
- 单向链表节点的删除
- 单项链表的节点插入
- 单项链表的反转
- 单向链表的串联
- 多项式的链表表示法
1 建立单向链表
现在,我们使用Java语言建立一个简单的单向链表。
每个节点的数据为学生的学号(int)、姓名(String)、成绩(int).如下:
学号 | 姓名 | 成绩 |
---|---|---|
01 | 小明 | 85 |
02 | 小明明 | 86 |
03 | 小红 | 87 |
04 | 小红红 | 80 |
05 | 小明 | 70 |
不要问为什么有两个小明,问就是重名了。
让每个节点包含一个学生数据,并且包含指向下一个节点的指针,使所有数据形成一个链表结构
我们先建立链表部分代码,在链表中定义两个Node节点类,分别指向链表第一个和最后一个节点,还定义了基本的3个方法:
方法名称 | 说明 |
---|---|
public boolean isEmpty() | 判断链表是否为空 |
public void print() | 打印链表节点 |
public void insert(int num1,String name1,int score1) | 将节点数据插入到链表 |
代码如下:(有详细注解)
import java.util.Scanner;
import java.io.*;
//定义节点
class Node{
int num;//学号
int score;//成绩
String name;//姓名
Node next;//指向下一节点
public Node(int num1,String name1,int score1){
num=num1;
score=score1;
name=name1;
next=null;
}
}
//构造链表
class LinkedList{
private Node first;
private Node last;
//判断链表是否为空
public boolean isEmpty(){
return first==null;
}
//打印链表节点
public void print(){
Node cur=first;
while(cur!=null)
{
System.out.println(cur.num+" "+cur.name+" "+cur.score);
cur=cur.next;
}
}
//插入节点
public void insert(int num1,String name1,int score1){
Node newNode=new Node(num1,name1,score1);
//如果链表为空,头指针和尾指针都指向该节点
if(isEmpty())
{
first=newNode;
last=newNode;
}
//如果不为空,尾节点指向该节点,并更新尾节点
else
{
last.next=newNode;
last=newNode;
}
}
}
接着我们在主函数中输入学生信息,并将节点信息打印出来
public class Main {
public static void main(String[] args) {
//建立5个学生成绩的单向链表
Scanner scan=new Scanner(System.in);
int num;
String name;
int score;
LinkedList list=new LinkedList();
//输入数据
System.out.println("请输入数据");
for(int i=0;i<5;i++)
{
num=scan.nextInt();
name=scan.next();
score=scan.nextInt();
list.insert(num,name,score);
}
//打印数据
System.out.println("节点数据如下");
list.print();
}
}
执行结果:
![c5ca9b0149d551c410501431ae0adbbe.png](https://img-blog.csdnimg.cn/img_convert/c5ca9b0149d551c410501431ae0adbbe.png)
2 单链表节点的删除
根据待删除节点在链表中的位置不同,有如下三种情形:
- 待删除节点是链表的第一个节点
此时,只要把头结点指针指向第二个节点即可。
if(first.num==delNode.num)
{
first=first.next;
}
![734fa1e95b9ae174a6b14afe69f1b881.png](https://img-blog.csdnimg.cn/img_convert/734fa1e95b9ae174a6b14afe69f1b881.png)
- 待删除节点是链表的中间节点
newNode=first;
tmp=first;
while(newNode.num!=delNode.num)
{
tmp=newNode;
newNode=newNode.next;
}
tmp.next=newNode.next;
3. 待删除节点是链表的最后一个节点
newNode=first;
while(newNode.next!=last)
newNode=newNode.next;
newNode.next=last.next;
//更新最后一个节点
last=newNode;
实现代码
public void delete(Node delNode){
Node newNode;
Node tmp;
//删除链表第一个节点
if(first.num==delNode.num)
{
first=first.next;
}
//删除链表最后一个节点
else if(last.num==delNode.num)
{
newNode=first;
while(newNode.next!=last)
newNode=newNode.next;
newNode.next=last.next;
//更新最后一个节点
last=newNode;
}
//删除中间节点
else
{
newNode=first;
tmp=first;
while(newNode.num!=delNode.num)
{
tmp=newNode;
newNode=newNode.next;
}
tmp.next=newNode.next;
}
}
在主函数中测试时,只需输入待删除节点的数据,构造一个新的节点,接着调用delete函数
//输入要删除学生成绩的学号System.out.println("输入删除节点数据");
int num1=scan.nextInt();
String name1=scan.next();
int score1=scan.nextInt();
//构造节点
Node delNode=new Node(num1,name1,score1);
//调用delete
list.delete(delNode);
结果如下:
3 单链表的节点插入
和节点的删除类似,也是按照位置的不同分为3种情况:
- 插入位置在链表的头部 这时只需将新节点的指针指向第一个节点,更新头结点
![464783d13b8ba2d895953b8f6ef49498.png](https://img-blog.csdnimg.cn/img_convert/464783d13b8ba2d895953b8f6ef49498.png)
- 插入位置在链表中间
如果插入位置在x与y之间,则将x指向该节点,该节点指针指向y.
3. 插入位置在链表尾部
将链表最后一个节点的指针指向该节点,并更新尾节点
![45d4149962933e349107d38554404828.png](https://img-blog.csdnimg.cn/img_convert/45d4149962933e349107d38554404828.png)
4 单向链表的反转
要将单链表反转,需要使用三个指针变量,before,current,last.
![40f8b070b05a7bbff1059e8327bd007c.png](https://img-blog.csdnimg.cn/img_convert/40f8b070b05a7bbff1059e8327bd007c.png)
代码如下:
class reverseLinkedList extends LinkedList{
public void reverse_print(){
Node current=first;
Node before=null;
System.out.println("反转后的链表:");
while(current!=null)
{
last=before;
before=current;
current=current.next;
before.next=last;
}
current=before;
while(current!=null)
{
System.out.println(current.num+" "+current.name+" "+current.score);
current=current.next;
}
}
}
结果如下:
5 单向链表的串联
实现单向链表的串联,指向将第一个链表最后一个节点指向第二个链表的第一个节点即可。
实现代码:
public LinkedList concatenate(LinkedList h1,LinkedList h2){
LinkedList ptr;
ptr=h1;
while(ptr.last.next!=null)
ptr.last=ptr.last.next;
ptr.last.next=h2.first;
return h1;
}
6 多项式的链表表示法
多项式的链表表示法主要是存储非零项目,并且每一项均符合以下数据结构:
例如;3x*x+6x-2的表示方法为:
![52a51e07f20454ff043f5cb80b612618.png](https://img-blog.csdnimg.cn/img_convert/52a51e07f20454ff043f5cb80b612618.png)
表示多项式的加法时,直接让指数相同的系数相加,指数只在一方的直接放到新链表中,例如
行 A=3x*x+6x-2
B=4(x*x)*x+16x+8
求A+B的算法如下
![99008ed0c9e68ced96057b0205ff1306.png](https://img-blog.csdnimg.cn/img_convert/99008ed0c9e68ced96057b0205ff1306.png)
至于实现代码,大家可以自己写一下。
8 小结
好了,以上就是本文的主要内容了。接下来会继续分享其他的链表结构,请大家持续关注!
那我们下一篇文章再见!
文:才辰
排版:才辰
![3965b1d91974c16cd7861aed8a0f6104.png](https://img-blog.csdnimg.cn/img_convert/3965b1d91974c16cd7861aed8a0f6104.png)