文章目录
1、链表
1.1 链表的介绍
- 1)链表是以节点的方式来存储
- 2)每个节点包含data域,next域:指向下一个节点
- 3)发现链表的各个节点不一定是连续存储
- 4)链表分头节点的链表和没有头节点的链表
2、单链表
步骤一、创建节点类(包含ni,name,nickName,next)
// 定义HeroNode,每一个HeroNode对象就是一个节点
class HeroNode{
public int no;
public String name;
public String nickName;
public HeroNode next; // 指向下一个节点
//构造器
public HeroNode(int no, String name, String nickName) {
this.no = no;
this.name = name;
this.nickName = nickName;
}
//为了显示方便,重写toString
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
", nickName='" + nickName +
'}';
}
步骤二、创建管理节点的类
// 定义一个LinkedList来管理HeroNode
class SingleLinkedList{
// 先初始化头节点,head节点不能动,也不能放其他具体信息
HeroNode head=new HeroNode(0,"","");
// 显示操作
// 添加操作
// 修改操作
// 删除操作
}
2.1、单链表的显示
//显示链表
public void list(){
// 首先判断链表是否为空
if(head.next==null){
System.out.println("链表为空~~~");
return;
}
// 创建一个辅助变量来遍历链表(因为head头节点不能改变)
HeroNode temp=head.next;
while (true){
if(temp==null){
System.out.println("链表遍历完了~~~");
break;
}
// 输出节点信息
System.out.println(temp.toString());
// 后移
temp=temp.next;
}
}
2.2、单链表的添加操作
2.2.1、直接添加到链表的尾部
// 添加节点到单链表
// 思路:不考虑编号顺序问题的话首先遍历到链表的最后,让最后节点的next指向新的节点
public void add(HeroNode heroNode){
// 创建一个辅助变量来遍历链表(因为head头节点不能改变)
HeroNode temp=head;
while(true){
// 找到链表的最后
if(temp.next==null){
break;
}
// 如果链表没有到最后,那么temp需要后移
temp=temp.next;
}
// 当循环退出之后,证明链表到最后了
// 将这个最后节点的next指向新节点
temp.next=heroNode;
}
进行测试:
public class SingleLinked {
public static void main(String[] args) {
// 进行测试
HeroNode hero1 = new HeroNode(1, "秦禹", "秦老黑");
HeroNode hero2 = new HeroNode(2, "可可", "心脏");
HeroNode hero3 = new HeroNode(3, "张子良", "人族智囊");
SingleLinkedList singleLinkedList=new SingleLinkedList();
// 添加节点
singleLinkedList.add(hero1);
singleLinkedList.add(hero2);
singleLinkedList.add(hero3);
// 显示链表数据
singleLinkedList.list();
}
}
// 定义一个LinkedList来管理HeroNode
class SingleLinkedList{
// 先初始化头节点,head节点不能动,也不能放其他具体信息
HeroNode head=new HeroNode(0,"","");
// 添加节点到单链表
// 思路:不考虑编号顺序问题的话首先遍历到链表的最后,让最后节点的next指向新的节点
public void add(HeroNode heroNode){
// 创建一个辅助变量来遍历链表(因为head头节点不能改变)
HeroNode temp=head;
while(true){
// 找到链表的最后
if(temp.next==null){
break;
}
// 如果链表没有到最后,那么temp需要后移
temp=temp.next;
}
// 当循环退出之后,证明链表到最后了
// 将这个最后节点的next指向新节点
temp.next=heroNode;
}
//显示链表
public void list(){
// 首先判断链表是否为空
if(head.next==null){
System.out.println("链表为空~~~");
return;
}
// 创建一个辅助变量来遍历链表(因为head头节点不能改变)
HeroNode temp=head.next;
while (true){
if(temp==null){
System.out.println("链表遍历完了~~~");
break;
}
// 输出节点信息
System.out.println(temp.toString());
// 后移
temp=temp.next;
}
}
}
// 定义HeroNode,每一个HeroNode对象就是一个节点
class HeroNode{
public int no;
public String name;
public String nickName;
public HeroNode next; // 指向下一个节点
//构造器
public HeroNode(int no, String name, String nickName) {
this.no = no;
this.name = name;
this.nickName = nickName;
}
//为了显示方便,重写toString
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
", nickName='" + nickName +
'}';
}
}
结果:
2.2.2、根据no插入到指定位置
实现代码:
//按照no顺序添加节点
public void addOrder(HeroNode heroNode){
HeroNode temp=head;
// 作为是否已经存在no相等的节点
boolean flag=false;
// 循环链表
while(true){
if(temp.next==null){
break;
}
//查找新节点在哪
if(temp.next.no>heroNode.no){ // 位置找到了在temp后面添加新节点
break;
}
if(temp.next.no==heroNode.no){ //编号已经存在,不能添加
flag=true;
break;
}
// temp后移
temp=temp.next;
}
if(flag){
System.out.println("该编号已经存在"+ heroNode.no+",不能添加该节点");
}else{
// 先把temp指向的下一个节点让新节点指向
heroNode.next=temp.next;
// 后temp指向的下一个节点设置为新节点
temp.next=heroNode;
}
}
执行结果:
2.3、单链表节点的修改
代码方法实现:
//修改节点的信息,通过no来修改即no是唯一的
public void update(HeroNode heroNode){
// 首先判断链表是否为空
if(head.next==null){
System.out.println("链表为空");
return;
}
// 找到需要修改的节点
HeroNode temp=head.next;
boolean flag=false;
while(true){
if(temp==null){
break;
}
if(heroNode.no==temp.no){
flag=true;
break;
}
temp=temp.next;
}
if(flag){
temp.name=heroNode.name;
temp.nickName=heroNode.nickName;
}
}
运行结果:
2.4、单链表节点的删除
思路:找到删除节点的前一个节点,让要删除的节点的前一个节点指向要删除节点的后一个节点
代码实现:
//删除节点
public void delete(int no){
if(head.next==null){
return;
}
HeroNode temp=head;
boolean flag=false;
while(true){
if(temp.next==null){
break;
}
// 找到要删除节点的前一个节点
if(temp.next.no==no){
flag=true;
break;
}
temp=temp.next;
}
if(flag){
// 让要删除的节点的前一个节点指向要删除节点的后一个节点
temp.next=temp.next.next;
}else{
System.out.println("未找到相对应的no节点");
}
}
运行结果:
3、双向链表
双向链表是在单链表的每个节点中,再设置一个指向其前驱节点的指针域。
创建节点类:
// 节点
class HeroNode2{
public int no;
public String name;
public String nickName;
// 指向后驱节点的指针
public HeroNode2 next;
// 指向前驱节点的指针
public HeroNode2 pre;
public HeroNode2(int no, String name, String nickName) {
this.no = no;
this.name = name;
this.nickName = nickName;
}
@Override
public String toString() {
return "HeroNode2{" +
"no=" + no +
", name='" + name + '\'' +
", nickName='" + nickName + '\'' +
'}';
}
}
创建管理双向节点的类:
//创建双链表
class DoubleLinkedList{
// 初始化一个头结点
private HeroNode2 head=new HeroNode2(0,"","");
// 添加操作
// 修改操作
// 删除操作
// 显示操作
}
3.1、双向链表的添加操作
3.1.1、一般默认添加到链表的尾部
思路:首先设置一个辅助节点来进行链表循环,如果链表为空,直接退出循环,否则一直循环到链表的最后退出循环,之后把temp的next指向新添加的节点,新添加的节点的pre指向temp。
代码实现:
// 在尾部添加元素
public void add(HeroNode2 heroNode2){
HeroNode2 temp=head;
while(true){
// 判断链表是否到最后
if(temp.next==null){
break;
}
// 没到最后,继续后移
temp=temp.next;
}
// 形成一个双向链表
temp.next=heroNode2;
heroNode2.pre=temp;
}
运行结果:
3.1.2、根据no插入到指定位置
代码实现:
// 根据no顺序添加节点
public void orderAdd(HeroNode2 heroNode2){
HeroNode2 temp=head;
while(true){
if(temp.next==null){
temp.next=heroNode2;
heroNode2.pre=temp;
break;
}
if(temp.next.no==heroNode2.no){
System.out.printf("已经存在编号%d,不能添加",heroNode2.no);
break;
}
// 找出第一个大于等于新增节点的no的节点temp的后驱节点,即在temp后面添加节点
if(temp.next.no>heroNode2.no){
// 1、先把temp赋值给新增节点的前驱
heroNode2.pre=temp;
// 2、把temp的后驱赋值给新增节点的后驱
heroNode2.next=temp.next;
// 3、把新增节点赋值给temp的后驱节点的前驱
temp.next.pre=heroNode2;
// 4、把新增节点赋值给temp的后驱
temp.next=heroNode2;
break;
}
temp=temp.next;
}
}
运行结果:
3.2、双向链表节点的修改
思路跟单链表差不多,自己理解理解。
代码实现:
// 修改heroNode2节点信息
public void update(HeroNode2 heroNode2){
if(head.next==null){
System.out.println("链表为空");
return;
}
HeroNode2 temp=head.next;
while(true){
if(temp==null){
// 没有找到要修改的节点
System.out.printf("没有找到编号为%d的节点,不能修改",heroNode2.no);
break;
}
// 找到要修改的节点
if(temp.no==heroNode2.no){
temp.name=heroNode2.name;
temp.nickName=heroNode2.nickName;
break;
}
temp=temp.next;
}
}
运行结果:
3.3、双向链表的删除
思路:相对于单链表需要找到删除节点的前一个节点删除,双向链表只要找到删除节点就可以进行删除。找到删除节点为temp,将temp的前一个节点的next指向temp的后一个节点,如果temp是最后一个节点,就不需要进行将temp的后一个节点的pre指向给temp的前一个节点。
代码实现:
// 根据no删除元素
public void delete(int no){
if(head.next==null){
System.out.println("链表为空");
return;
}
HeroNode2 temp=head.next;
boolean flag=false;
while(true){
if(temp==null){
break;
}
if(temp.no==no){
flag=true;
break;
}
temp=temp.next;
}
if(flag){
// 双向链表的节点删除(不需要向单链表那样先找出要删除节点的前一个节点)
temp.pre.next=temp.next;
// 如果是最后一个节点,就不需要执行下面的这句话,否则出现空指针
if(temp.next!=null){
temp.next.pre=temp.pre;
}
}else{
System.out.printf("没有编号为%d的节点",no);
}
}