**定义:**单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。
链表中的数据是以结点来表示的,
每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),元素就是存储数据的存储单元,
指针就是连接每个结点的地址数据
本篇文章只是记录一下学习链表和使用代码实现,文章有写的不好或不对的可以指出,初次写稿,多多见谅
我们开始吧:
1.首先我们需要理解链表的数据结构的组成吧,如下图
![在这里插入图片描述](https://img-blog.csdnimg.cn/2020051921011868.jpg#pic_center)
链表中的每一个节点都包含两个部分: **data(数据域)和next(下一个节点指向)**
2. 链表的优缺点
优点:
1. 删除和修改快(相对于数组数据结构来说)
2. 链表存储是分散的空间地址(数组是连续性的存储地址,需要-一开始指定存储大小)
3. 扩展性好,
缺点:
1.查询慢,因为查询需要从头开始遍历查询(不能按索引位置查询)
3.代码实现如下
//定义一个链表类 基础类
class HearNode {
public Integer code;
public String name;
public String nickName;//以上是data数据域的属性
public HearNode next; //指针域
public HearNode(Integer code, String name, String nickName) {
this.code = code;
this.name = name;
this.nickName = nickName;
}
@Override
public String toString() {
return "HearNode{" +
"code=" + code +
", name='" + name + '\'' +
", nickName='" + nickName + '\'' +
'}';
}
}
再定义一个实现链表的curd操作方法类
//封装方法
class LianBiaoDemo {
//初始化链表 定义头结点
HearNode head = new HearNode(null, "", "");
/**
* 1 首先需要找到链表最后一个节点 将该节点next指向插入的节点数据即可
*
* @param hearNode
*/
public void addList(HearNode hearNode) {
HearNode hea = head;
//如果hea 的下一个节点为null 则表示已经到了尾节点
while (hea != null) {
if (hea.next == null) {
break;
}
hea = hea.next;
}
hea.next = hearNode;
}
/**
* 获取头节点信心
*/
public HearNode getFirst() {
if (head.next == null) {
System.out.println("该链表是空的 ~~~");
}
System.out.println(head.next);
return head.next;
}
/**
* 获取尾节点信息
*/
public void getLast() {
if (head.next == null) {
System.out.println("该链表是空的 ~~~");
}
HearNode last = head;
while (true) {
if (last.next == null) {
break;
}
last = last.next;
}
System.out.println(last);
}
/**
* 获取链表的有效节点数
*
* @return
*/
public int getCount() {
//首先做链表非空判断
if (head.next == null) {
System.out.println("此链表为空的 ~~~");
return 0;
}
HearNode hea = head;
//获取链表的长度
int i = 0;
while (hea.next != null) {
hea = hea.next;
i++;
}
return i;
}
/**
* 链表反转
*/
public void revserNodeList() {
//先判断节点个数是否为等于1或者为空
if (head.next == null || head.next.next == null) {
return;
}
//定义一个辅助变量指针 来遍历原始的链表
HearNode hea = head.next;
//定义一个新的链表 只想当前节点【hea】的下一个节点
HearNode next = null;
//新的链表的头节点信息
HearNode newHead = new HearNode(null, "", "");
//遍历原来的链表,每遍历一个节点,就将其取出,并放在新的链表的newHead 的最前端
while (hea != null) {
//记录链表指针 记录信息
next = hea.next;
//新链表的头节点指向取出的数据信息
hea.next = newHead.next;
//获取到最新的节点信息放到变量链表的头节点
newHead.next = hea;
//循环遍历
hea = next;
}
// 将链表的头节点指向变量节点的头节点 head.next -> newHead.next
head.next = newHead.next;
}
/**
* 获取链表中的第N个节点信息
* 1. 首先需要获取到链表的总的长度 需要先遍历一边
* 2.定义一个变量接收要获取的第几个节点信息 index
* 3.得到长度之后 从链表的第一个开始遍历(总长度 - index)个 就可以得到
* 4.如果找到就返回 没有找到就返回空
*
* @return
*/
public HearNode getIndex(int index) {
//首先做链表非空判断
if (head.next == null) {
System.out.println("此链表为空的 ~~~");
return null;
}
//获取链表的长度
int i = getCount();
//然后判断 链表长度与获取指定index作比较 如果为空或者index为负数 则直接返回
if (i < index || index <= 0) {
System.out.println("该index超出链表的长度");
return null;
}
HearNode hea = head.next;
for (int j = 0; j < i - index; j++) {
hea = hea.next;
}
return hea;
}
/**
* 从尾打印链表数据
* @param
*/
public void StackInfo(){
//判断链表是否为空
if (head.next ==null){
return;
}
//获取头节点信息
HearNode hea=head;
Stack stack=new Stack();
while (hea.next !=null){
hea=hea.next;
//进栈
stack.push(hea);
}
while (!stack.empty()){
// 出栈
System.out.println("打印出来"+stack.pop());
}
}
/**
* 链表插入时按照大小排序
* 1 我们采用头结点的形式进行添加数据 所以需要定义一个头结点信息 但是这个头结点不做修改
* 2. 定义一个辅助变量 flag 来判断 循环接节点与插入的节点大小比对 如果当前节点的下一个节点比插入节点大 则将插入的节点放置到当前节点下个节点前即可
*
* @param hearNode
*/
public void sortList(HearNode hearNode) {
//定义一个头结点
HearNode hea = head;
boolean flag = false;
//hea不为空则循环继续
while (hea != null) {
//如果hea的下一个节点为null 则表示到达最后一个节点
if (hea.next == null) {
break;
}
//这里也可以做一个判断 如果节点相同则不让它添加
//判断 如果当前节点code 大于当前code 则将当前的数据放在当前节点之前
//我们删除一个节点 需要找到删除节点的前一个节点
if (hea.next.code > hearNode.code) {
flag = true;
break;
}
hea = hea.next;
}
//如果flag为ture 则将当前插入的数据放到当前节点之后
if (flag) {
hearNode.next = hea.next;
hea.next = hearNode;
} else {
hea.next = hearNode;
}
}
/**
* 删除节点信息
*
* @param code
*/
public void delteNode(int code) {
//判断当前链表是否为空
if (head.next == null) {
System.out.println("当前链表为空~~");
}
//定义一个变量
HearNode hea = head;
//定义一个标志位 记录查询到删除的code
boolean flag = false;
while (hea != null) {
if (hea.next == null) {
break;
}
//如果当前节点的code等于删除的code 则表示找到了记录信息
if (hea.next.code == code) {
flag = true;
break;
}
hea = hea.next;//后移遍历
}
//判断标志位是否为ture
if (flag) {
//表示找到了删除的数据信息
hea.next = hea.next.next;
} else {
System.out.println("未找到删除的节点信息");
}
}
/**
* 查询连表数据信息
*/
public void selectList() {
if (head.next == null) {
System.out.println("当前链表为空~~");
return;
}
HearNode hea = head.next;
while (hea != null) {
System.out.println(hea);
hea = hea.next;
}
}
/**
* 修改节点信息
* 1 首先需要循环遍历 去匹配找到需要修改的节点信息
*
* @param updateCode
*/
public void updateCode(int code, HearNode updateCode) {
//判断头结点的下一个是否为空,如果为空则直接返回
if (head.next == null) {
return;
}
HearNode hea = head;
//定义一个辅助变量 记录是否找到修改信息的数据
boolean flag = false;
while (hea != null) {
if (hea.next == null) {
break;
}
//判断当前节点的下一个数据的code是否修改的数据信息
if (hea.next.code == code) {
flag = true;
break;
}
hea = hea.next;//循环遍历
}
//如果为ture则表示找到了
if (flag) {
hea.next.name = updateCode.name;
hea.next.nickName = updateCode.nickName;
} else {
System.out.println("未找到需要修改的信息数据");
}
}
最后我们再对方法进行测试,如下:
public class LianBiao {
public static void main(String[] args) {
LianBiaoDemo lianBiaoDemo = new LianBiaoDemo();
//进行数据添加操作
HearNode node = new HearNode(9, "wang", "~~~");
HearNode node01 = new HearNode(15, "li", "~~~");
HearNode node02 = new HearNode(3, "tang", "~~~");
HearNode node04 = new HearNode(6, "tang01", "~~~");
HearNode node05 = new HearNode(6, "tang02", "~~~");
lianBiaoDemo.sortList(node01);
lianBiaoDemo.sortList(node);
lianBiaoDemo.sortList(node02);
lianBiaoDemo.sortList(node05);
lianBiaoDemo.sortList(node04);
//查询方法
lianBiaoDemo.selectList();
//删除
System.out.println("删除钱");
lianBiaoDemo.delteNode(9);
lianBiaoDemo.delteNode(15);
lianBiaoDemo.selectList();
//修改
System.out.println("修改前的数据信息~~~~");
HearNode newHearNode = new HearNode(3, "修改", "修改成功");
lianBiaoDemo.updateCode(3, newHearNode);
lianBiaoDemo.selectList();
//1.获取头节点信息
System.out.println("头节点信息为====》");
lianBiaoDemo.getFirst();
//2.获取尾节点信息
System.out.println("尾节点信息======》");
lianBiaoDemo.getLast();
//3.求单链表的有效节点数
System.out.println("链表的有效长度:" + lianBiaoDemo.getCount());
//4.获取链表的倒数第n个节点信息
System.out.println("获取指定indexe链表的数据===》" + lianBiaoDemo.getIndex(5));
//5.单链表的反转 例如 123 ==》 321 123456====》654321 类似与这种反转
/**
* 反转的思路如下
* 1.方法有很多 可以利用链表 +队列 来实现反转操作
* 这个方法还是用链表来实现 不过需要借助一个链表来进行
* 2. 定义一个新的链表
*/
System.out.println("反转链表~~");
lianBiaoDemo.revserNodeList();
lianBiaoDemo.selectList();
//6从尾到头打印单链表 (要求方式: 1. 反向遍历 2. stack栈)
/**
* 可以利用栈的先进后出进行实现
*/
System.out.println("反转");
lianBiaoDemo.StackInfo();
}
}