学习数据结构笔记=====>链表
Posted 小智RE0
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了学习数据结构笔记=====>链表相关的知识,希望对你有一定的参考价值。
学习来源–>传送门–>尚硅谷Java数据结构与java算法(Java数据结构与算法)
链表存储结构 不一定就是连续的;比如下面这个单链表;
链表由一个个地节点组成; data 存放实际数据,next类似于一个指针;指向下一个节点;
最后一个节点的指针next指向 null;
还有,链表不一定都需要头节点;
ml
单向链表实现
案例,完成一个存放英雄的链表,可以增删改查的那种单链表实现;
创建的结点存放时,会保存英雄的编号,姓名,以及指向下一个英雄的指针;
先完成创建链表,添加节点;然后遍历链表;
public class LinkTest01 {
//用节点存放英雄;
class HeroNode {
//编号;
private int serial;
//姓名,
private String name;
//指针;
private HeroNode next;
//初始化;
public HeroNode(int serial, String name) {
this.serial = serial;
this.name = name;
}
//输出节点;
@Override
public String toString() {
return "HeroNode{" + "serial=" + serial + ", name='" + name + '}';
}
}
//链表;
class OneDirectionLink {
//链表头结点; 空数据;
private HeroNode headNode = new HeroNode(0, "");
//判断链表为空;
public boolean isEmpty() {
return headNode == null;
}
//获取头结点;
public HeroNode getHeadNode() {
return headNode;
}
//添加新节点时,直接尾插法; 在后面添加即可; 让指向null的节点 指向这个添加的节点,添加的节点指向 null;
public void addNode(HeroNode heroNode) {
//把头结点存入临时节点;
HeroNode temp = headNode;
//找最后一个;
while (temp.next != null) {
//节点后移;
temp = temp.next;
}
//找到了,连接即可;
temp.next = heroNode;
heroNode.next = null;
}
//遍历链表;
public void getAllLink() {
if (isEmpty()) {
System.out.println("链表为空,不遍历");
return;
}
//遍历时;
//头结点为空数据,不用输出;
HeroNode tempNode = headNode.next;
//遍历;结束条件;
while (tempNode != null) {
System.out.println(tempNode);
tempNode = tempNode.next;
}
}
}
}
测试:
//测试链表;
public static void main(String[] args) {
LinkTest01 test = new LinkTest01();
//创建节点;
HeroNode heroNode0 = test.new HeroNode(10, "杰克");
HeroNode heroNode1 = test.new HeroNode(8, "刘备");
HeroNode heroNode2 = test.new HeroNode(45, "马克");
HeroNode heroNode3 = test.new HeroNode(489, "张飞");
HeroNode heroNode4 = test.new HeroNode(32, "关羽");
//创建链表;
OneDirectionLink oneDirectionLink = test.new OneDirectionLink();
//添加;
oneDirectionLink.addNode(heroNode0);
oneDirectionLink.addNode(heroNode1);
oneDirectionLink.addNode(heroNode2);
oneDirectionLink.addNode(heroNode3);
oneDirectionLink.addNode(heroNode4);
//遍历;
oneDirectionLink.getAllLink();
}
HeroNode{serial=10, name='杰克}
HeroNode{serial=8, name='刘备}
HeroNode{serial=45, name='马克}
HeroNode{serial=489, name='张飞}
HeroNode{serial=32, name='关羽}
现在需要完成一个新的需求;添加节点时,按照英雄的编号大小去添加,而不是之前那样直接添加到尾部;那么在添加之前就得遍历链表来确定编号;决定好把新节点放到哪个位置;
直接在链表OneDirectionLink
类中添加方法
//按照顺序添加节点;
public void addNodeOrder(HeroNode heroNode){
//先把头结点存入临时节点;
HeroNode temp = headNode;
//放置一个标志位;
boolean flag = false;
//遍历; 找位置
while (true){
//结束条件;
if(temp.next==null){
break;
}
//比较大小; 得出要添加的节点位于 temp 与 temp.next 之间;
if(temp.next.serial >heroNode.serial){
break;
}
//编号相同;不许添加;
else if(temp.next.serial == heroNode.serial) {
flag = true;
break;
}
//移动临时节点;
temp = temp.next;
}
//对标志位进行判断;
if(flag){
//不可添加节点;
System.out.println("该节点英雄已存在->"+heroNode.serial);
}else {
//添加;
heroNode.next = temp.next;
temp.next = heroNode;
}
}
测试效果
//测试链表;
public static void main(String[] args) {
LinkTest01 test = new LinkTest01();
//创建节点;
HeroNode heroNode0 = test.new HeroNode(10, "杰克");
HeroNode heroNode1 = test.new HeroNode(8, "刘备");
HeroNode heroNode2 = test.new HeroNode(45, "马克");
HeroNode heroNode3 = test.new HeroNode(489, "张飞");
HeroNode heroNode4 = test.new HeroNode(32, "关羽");
//创建链表;
OneDirectionLink oneDirectionLink = test.new OneDirectionLink();
//添加;
oneDirectionLink.addNodeOrder(heroNode0);
oneDirectionLink.addNodeOrder(heroNode1);
oneDirectionLink.addNodeOrder(heroNode2);
oneDirectionLink.addNodeOrder(heroNode3);
oneDirectionLink.addNodeOrder(heroNode4);
//遍历;
oneDirectionLink.getAllLink();
}
添加的时候是有序的;
HeroNode{serial=8, name='刘备}
HeroNode{serial=10, name='杰克}
HeroNode{serial=32, name='关羽}
HeroNode{serial=45, name='马克}
HeroNode{serial=489, name='张飞}
现在对这个单链表进行修改;由编号得到要修改的节点;仅限于对英雄名称的修改;
在链表OneDirectionLink
类中添加修改方法;
//对单链表进行修改;
public void updateLink(HeroNode newNode){
//先判空;
if(isEmpty()){
System.out.println("抱歉,链表为空");
return;
}
//修改即可;
HeroNode temp = headNode.next;
//是否可修改的标志位;
boolean flag =false;
while (true){
//遍历结束条件;
if(temp==null){
break;
}
//找编号;
else if(temp.serial == newNode.serial){
flag = true;
break;
}
//移动节点;
temp = temp.next;
}
//根据标志位决定是否修改;
if(flag){
//修改;
temp.name = newNode.name;
}else {
System.out.println("抱歉,您要找的节点不存在==>"+newNode.serial);
}
}
测试修改
//测试链表;
public static void main(String[] args) {
LinkTest01 test = new LinkTest01();
//创建节点;
HeroNode heroNode0 = test.new HeroNode(10, "杰克");
HeroNode heroNode1 = test.new HeroNode(8, "刘备");
HeroNode heroNode2 = test.new HeroNode(45, "马克");
HeroNode heroNode3 = test.new HeroNode(489, "张飞");
HeroNode heroNode4 = test.new HeroNode(32, "关羽");
//创建链表;
OneDirectionLink oneDirectionLink = test.new OneDirectionLink();
//添加;
oneDirectionLink.addNodeOrder(heroNode0);
oneDirectionLink.addNodeOrder(heroNode1);
oneDirectionLink.addNodeOrder(heroNode2);
oneDirectionLink.addNodeOrder(heroNode3);
oneDirectionLink.addNodeOrder(heroNode4);
//遍历;
oneDirectionLink.getAllLink();
System.out.println("--------修改节点测试------------");
//修改不存在的;
oneDirectionLink.updateLink(test.new HeroNode(15,"阿杰"));
//修改存在的;
oneDirectionLink.updateLink(test.new HeroNode(10,"阿杰"));
//遍历查看
oneDirectionLink.getAllLink();
}
修改不存在的节点,会提示信息;
HeroNode{serial=8, name='刘备}
HeroNode{serial=10, name='杰克}
HeroNode{serial=32, name='关羽}
HeroNode{serial=45, name='马克}
HeroNode{serial=489, name='张飞}
--------修改节点测试------------
抱歉,您要找的节点不存在==>15
HeroNode{serial=8, name='刘备}
HeroNode{serial=10, name='阿杰}
HeroNode{serial=32, name='关羽}
HeroNode{serial=45, name='马克}
HeroNode{serial=489, name='张飞}
完成对节点的删除,注意删除时把指针的next的指向调整好;
先找待删除结点的前一个结点; 然后把这个结点的指针next指向到待删除结点的下一个节点;
在链表OneDirectionLink
类中添加删除方法;
//删除结点;
public void removeNode(int serial){
//头结点存入临时节点;
HeroNode temp = headNode;
//放置标志位,判断是否找到待删除结点;
boolean flag =false;
//遍历找结点;
while (true){
//遍历结束条件;
if(temp.next == null){
break;
}
//找编号是否相同;
if(temp.next.serial == serial){
flag = true;
break;
}
//移动节点;
temp = temp.next;
}
//根据标志位决定是否要删除;
if(flag){
temp.next = temp.next.next;
}else {
System.out.println("要删除的节点不存在->"+serial);
}
}
测试删除结点的方法
//测试链表;
public static void main(String[] args) {
LinkTest01 test = new LinkTest01();
//创建节点;
HeroNode heroNode0 = test.new HeroNode(10, "杰克");
HeroNode heroNode1 = test.new HeroNode(8, "刘备");
HeroNode heroNode2 = test.new HeroNode(45, "马克");
HeroNode heroNode3 = test.new HeroNode(489, "张飞");
HeroNode heroNode4 = test.new HeroNode(32, "关羽");
//创建链表;
OneDirectionLink oneDirectionLink = test.new OneDirectionLink();
//添加;
oneDirectionLink.addNodeOrder(heroNode0);
oneDirectionLink.addNodeOrder(heroNode1);
oneDirectionLink.addNodeOrder(heroNode2);
oneDirectionLink.addNodeOrder(heroNode3);
oneDirectionLink.addNodeOrder(heroNode4);
//遍历;
oneDirectionLink.getAllLink();
System.out.println("-----------删除结点测试---------------");
oneDirectionLink.removeNode(10);
//遍历
oneDirectionLink.getAllLink();
}
测试结果
HeroNode{serial=8, name='刘备}
HeroNode{serial=10, name='杰克}
HeroNode{serial=32, name='关羽}
HeroNode{serial=45, name='马克}
HeroNode{serial=489, name='张飞}
-----------删除结点测试---------------
HeroNode{serial=8, name='刘备}
HeroNode{serial=32, name='关羽}
HeroNode{serial=45, name='马克}
HeroNode{serial=489, name='张飞}
单向链表相关题
1.求出单链表的实际存放节点个数
实际上,本可以在刚才的案例中定义一个数 size,记录节点的个数;添加时size+1 ;删除时size-1;
那就不加了;直接遍历也行;
在刚才的结点和链表基础上,在测试类中定义静态方法;
//计算节点的个数;
public static int getNodeSize(HeroNode headNode){
if(headNode.next == null){
System.out.println("这是空链表");
return 0;
}
int size = 0;
//头节点 指向 临时节点;
HeroNode temp =headNode.next;
while (temp!=null){
size++;
//移动操作的节点;
temp = temp.next;
}
return size;
}
2. 查询单链表的倒数第k个节点
首先分析一下;
这个方法,会有两个参数; 一个是链表的头结点;一个是倒数第k个 数;先把链表遍历一下;得出链表的长度;size;
然后再次遍历 (size - k) 即可得到想要查询的节点;
在测试类中定义静态方法;
//查询链表的倒数第K个节点;
public static HeroNode getTheKNode(HeroNode head,int k){
//先对链表判空,以及指定的位置判断;
if(head.next == null || k<=0){
return null;
}
//计算数量;
int size = getNodeSize(head);
//若指定的位置已经大于链表的长度;则直接返回null;
if(size<k){
return null;
}
//还是临时节点去活动;
HeroNode temp =head.next;<以上是关于学习数据结构笔记=====>链表的主要内容,如果未能解决你的问题,请参考以下文章