Java实现单链表(附源码)
文章目录
- Java实现单链表(附源码)
- 前言
- 一、学习目的
- 二、主要内容
- 1.定义单链表的存储结构
- 2.单链表的基本操作及实现
- 3.完整代码
- 总结
前言
此文章主要实现单链表的基本操作。
我也是一位学习者,如果有任何问题,欢迎私信交流学习!
提示:以下是本篇文章正文内容,下面案例可供参考
一、学习目的
- 理解线性表的逻辑结构;
- 理解单链表的存储结构特点,掌握单链表的存储分配要点;
- 掌握单链表的基本操作及实现,并能正确分析其时间复杂度;
二、主要内容
1.定义单链表的存储结构
首先我们需要定义两个类:结点类(Node)、单链表(SingleLinkList)
结点类主要用于存储数据和下一个结点的地址
单链表主要用于存储结点以及基本操作
代码如下(示例):
结点类(Node)
public class LinkListNode {
private Integer data; // 结点的数据域
private LinkListNode next; // 下一个结点
}
单链表(SingleLinkList)
public class SingleLinkList {
private LinkListNode head;//定义单链表的头结点
private int length;//用来记录单链表的长度
}
2.单链表的基本操作及实现
- 初始化单链表(无参和有参)
我对链表的初始化有点不太理解,因为存在有参和无参构造,但是在java语言中本来就存在无参构造;
这里就强行解释一波:
· 无参构造理解为初始化单链表(包含头结点)
· 有参构造理解为初始化单链表和首元结点(包含头结点和首元结点)
/**
* 单链表的初始化 init() 无参
*/
public SingleLinkList(){
this.head = new LinkListNode();
}
/**
* 单链表的初始化 init() 有参
* */
public SingleLinkList(Integer data,LinkListNode next){
this.head = new LinkListNode();
LinkListNode node = new LinkListNode();
node.setData(data);
node.setNext(next);
head.setNext(node);
}
- 求单链表长度
在我的单链表类中属性包含了长度,这样就可以通过空间换时间,当需要获取单链表的长度时,可以直接访问属性而无需遍历单链表 。
/**
* 求单链表长度
*/
public int getLength(){
return length;
}
- 新增:默认在最后插入一个数据元素
创建一个p指针,用于遍历单链表找到最后一个元素,然后将新结点的地址赋给最后一个结点的下一个地址。
这种情况下是这样的:
· 单链表:1,2,3,4,5
· 新增:插入“99”
· 结果:1,2,3,4,5,99
/**
* 新增:默认在最后插入一个数据元素;
*/
public LinkListNode insert(Integer data){
LinkListNode newNode = new LinkListNode(data);
LinkListNode p = head;
while (p.getNext()!=null){
p = p.getNext();
}
p.setNext(newNode);
length++;
return newNode;
}
- 新增:在位置i插入一个数据元素
这个要首先判断这个位置i是否大于了单链表的长度,比如此时单链表的长度为4,输入的位置i为6,显然位置5都还没有结点,所以我默认将这个新结点添加在单链表的末尾;
这种情况下是这样的:
· 单链表:1,2,3,4,5
· 新增:在第3个位置插入“99”
· 结果:1,99,2,3,4,5
/**
* 新增:在位置i插入一个数据元素;
*/
public void insertByIndex(int index,Integer data){
// 如果位置i大于了单链表的长度 或者 位置不合理 则直接将新结点添加到最后
if(index>length||index-1<0){
insert(data);
return;
}
index--;
// 将指针p指向首元结点
LinkListNode p = head;
while (index!=0){
p=p.getNext();
index--;
}
LinkListNode newNode = new LinkListNode(data,p.getNext());
p.setNext(newNode);
length++;
}
- 查找:按位置查找
第一步:判定输入的位置是否大于单链表长度(大于则直接返回null)
第二步:通过p指针移动到指定的位置,获取数据元素
/**
* 查找:按位置查找
*/
public Integer getByIndex(int index){
// 如果查找的元素大于了单链表的长度则返回null
if(index>length){
return null;
}
// 将指针p指向头结点
LinkListNode p = head;
while (index!=0){
p=p.getNext();
index--;
}
return p.getData();
}
- 查找:按值查找
通过移动p指针,取出每一个结点的数据元素与输入的值进行对比,如果发现数据匹配的结点,就返回结点位置;如果单链表都遍历完了还没有找到就返回0,因为我的单链表位置是从1开始计算的,返回0就表示未找到。
/**
* 查找:按值查找
*/
public int getByData(Integer data){
// 将指针p指向首元结点
LinkListNode p = head;
int index = 0;
while (p.getNext()!=null){
p=p.getNext();
index++;
if(p.getData().equals(data)){
return index;
}
}
if(index==length&&!p.getData().equals(data)){
return 0;
}
return index;
}
- 查找:遍历单链表
创建p结点做为指针,遍历单链表。
/**
* 查找:遍历单链表
*/
public void traverse(){
LinkListNode p = head;
while (p.getNext()!=null){
p = p.getNext();
System.out.println("结点值:"+p.getData());
}
}
- 删除:按位置i删除数据元素
第一步:判定位置i是否大于单链表的长度(是就返回null)
第二步:将p指针移动到被删除元素的前一个位置,主要是为了断开删除元素的连接,连接下一个结点的地址。
/**
* 删除:按位置i删除数据元素;
*/
public Integer deleteByIndex(int index){
// 如果位置i大于了单链表的长度则返回null
if(index>length||index-1<0){
return null;
}
// 提前将index-- 是为了将p指针移到被删除元素的前一个位置
index--;
// 将指针p指向头结点
LinkListNode p = head;
while (index!=0){
p=p.getNext();
index--;
}
int res = p.getNext().getData();
p.setNext(p.getNext().getNext());
length--;
return res;
}
- 合并链表
直接将第二个链表的首元结点的地址赋值给第一个链表的最后一个结点的地址域。
/**
* 合并链表
*/
public void marge(SingleLinkList singleLinkList){
LinkListNode p = head;
length=length+singleLinkList.length;
while (p.getNext()!=null){
p = p.getNext();
}
p.setNext(singleLinkList.head.getNext());
}
3.完整代码
结点类:LinkListNode
package experiment_01;
public class LinkListNode {
private Integer data; // 结点的数据域
private LinkListNode next; // 下一个结点
public LinkListNode(){
}
public LinkListNode(Integer data){
this.data = data;
this.next = null;
}
public LinkListNode(Integer data,LinkListNode next){
this.data = data;
this.next = next;
}
public Integer getData() {
return data;
}
public void setData(Integer data) {
this.data = data;
}
public LinkListNode getNext() {
return next;
}
public void setNext(LinkListNode next) {
this.next = next;
}
}
单链表类:SingleLinkList
public class SingleLinkList {
private LinkListNode head;//定义单链表的头结点
private int length;//用来记录单链表的长度
/**
* 单链表的初始化 init() 无参
*/
public SingleLinkList(){
this.head = new LinkListNode();
}
/**
* 单链表的初始化 init() 有参
* */
public SingleLinkList(Integer data,LinkListNode next){
this.head = new LinkListNode();
LinkListNode node = new LinkListNode();
node.setData(data);
node.setNext(next);
head.setNext(node);
}
/**
* 求单链表长度
*/
public int getLength(){
return length;
}
/**
* 新增:默认在最后插入一个数据元素;
*/
public LinkListNode insert(Integer data){
LinkListNode newNode = new LinkListNode(data);
LinkListNode p = head;
while (p.getNext()!=null){
p = p.getNext();
}
p.setNext(newNode);
length++;
return newNode;
}
/**
* 新增:在位置i插入一个数据元素;
*/
public void insertByIndex(int index,Integer data){
// 如果位置i大于了单链表的长度 或者 位置不合理 则直接将新结点添加到最后
if(index>length||index-1<0){
insert(data);
return;
}
index--;
// 将指针p指向首元结点
LinkListNode p = head;
while (index!=0){
p=p.getNext();
index--;
}
LinkListNode newNode = new LinkListNode(data,p.getNext());
p.setNext(newNode);
length++;
}
/**
* 查找:按位置查找
*/
public Integer getByIndex(int index){
// 如果查找的元素大于了单链表的长度则返回null
if(index>length){
return null;
}
// 将指针p指向头结点
LinkListNode p = head;
while (index!=0){
p=p.getNext();
index--;
}
return p.getData();
}
/**
* 查找:按值查找
*/
public int getByData(Integer data){
// 将指针p指向首元结点
LinkListNode p = head;
int index = 0;
while (p.getNext()!=null){
p=p.getNext();
index++;
if(p.getData().equals(data)){
return index;
}
}
if(index==length&&!p.getData().equals(data)){
return 0;
}
return index;
}
/**
* 查找:遍历单链表
*/
public void traverse(){
LinkListNode p = head;
while (p.getNext()!=null){
p = p.getNext();
System.out.println("结点值:"+p.getData());
}
}
/**
* 删除:按位置i删除数据元素;
*/
public Integer deleteByIndex(int index){
// 如果位置i大于了单链表的长度则返回null
if(index>length||index-1<0){
return null;
}
// 提前将index-- 是为了将p指针移到被删除元素的前一个位置
index--;
// 将指针p指向头结点
LinkListNode p = head;
while (index!=0){
p=p.getNext();
index--;
}
int res = p.getNext().getData();
p.setNext(p.getNext().getNext());
length--;
return res;
}
/**
* 合并链表
*/
public void marge(SingleLinkList singleLinkList){
LinkListNode p = head;
length=length+singleLinkList.length;
while (p.getNext()!=null){
p = p.getNext();
}
p.setNext(singleLinkList.head.getNext());
}
}
测试类:LinkListTest
import java.util.Scanner;
public class LinkListTest {
public static void main(String[] args){
// 初始化单链表
SingleLinkList singleLinkList = new SingleLinkList();
// 在链表尾部新增结点
singleLinkList.insert(15);
singleLinkList.insert(16);
singleLinkList.insert(17);
singleLinkList.insert(18);
Scanner scanner = new Scanner(System.in);
int operation = 0;
printList(singleLinkList);
while (operation!=-1) {
System.out.println("请选择一个操作:\n 1、遍历输出单链表 \n 2、根据位置查找结点的值 \n 3、根据值查找结点的位置 " +
"\n 4、在指定位置插入一个数据元素 \n 5、根据位置删除结点 \n 6、合并一个链表给你看看就行 \n 7、退出程序");
operation = scanner.nextInt();
switch (operation) {
case 1:
// 遍历输出单链表
printList(singleLinkList);
break;
case 2:
System.out.println("请问你要查找第几个结点的值?");
int index = scanner.nextInt();
System.out.println("第" + index + "个结点的值:" + singleLinkList.getByIndex(index));
break;
case 3:
System.out.println("请问你要查找值为多少的结点位置?");
Integer data = scanner.nextInt();
System.out.println("值为" + data + "的结点位置:" + singleLinkList.getByData(data));
break;
case 4:
System.out.println("请问你要在第几个位置插入结点?");
index = scanner.nextInt();
System.out.println("请问你要插入值为多少的结点?");
data = scanner.nextInt();
singleLinkList.insertByIndex(index, data);
break;
case 5:
System.out.println("请问你要删除哪个位置的结点?");
index = scanner.nextInt();
singleLinkList.deleteByIndex(index);
break;
case 6:
SingleLinkList singleLinkList2 = new SingleLinkList();
singleLinkList2.insert(1);
singleLinkList2.insert(2);
singleLinkList2.insert(3);
singleLinkList.marge(singleLinkList2);
break;
default:
System.exit(0);
}
}
}
public static void printList(SingleLinkList singleLinkList){
System.out.println("单链表的长度:"+singleLinkList.getLength());
singleLinkList.traverse();
}
}
希望大家可以一次性运行成功喔!
总结
对不起了大家,今天没时间写了,下次补上。