基于Java实现双向链表
作者:fan儿 发布时间:2022-11-17 11:39:16
本文实例为大家分享了Java实现双向链表的具体代码,供大家参考,具体内容如下
双向链表与单链表的对比:
1、单向链表查找只能是一个方向,双向链表可以向前或者向后查找
2、单向链表不能自我删除,需要靠辅助节点**(即需要通过找到要删除的节点的前一个节点,通过该节点进行删除的操作,而双向链表只需找到要删除的节点就行了)**。双向链表可以自我删除
双向链表示意图
分析(代码实现原理):temp为辅助节点(因为头节点不可动)
1、遍历:方式与单链表一致,但是是双向的,可以向前,也可以向后
2、添加(默认添加到最后面)
(1)先找到链表的最后一个节点
(2)temp.next=newnode
(3)newnode.pre=temp
3、修改:思路与原理与单链表一致
4、删除:
(1)因为是双向链表,可以自我删除该节点
(2)找到要删除的节点,假设这个节点为temp
(3)temp.pre.next=temp.next
(4)temp.next.pre=temp.pre
添加节点(按顺序):
步骤:
(1)找到要添加节点位置的前一个节点(temp)
(2)node.next=temp.next
(3)temp.next.pre=node
(4)temp.next=node
(5)node.pre=temp
代码实现:
public class DoubleLinkedList {
//创建头结点。表示链表的头
private Node Head=new Node(0,"","");
//返回头结点
public Node getHead() {
return Head;
}
//AddNode1:添加节点到单链表的尾部
//思路:当不考虑节点顺序
//1、找到链表的最后一个节点
//2、将最后这个节点的Next指向新节点
public void AddNode1(Node node) {
//因为头节点不能动,所以需要一个辅助节点遍历
Node temp=Head;
while(true) {
//找到链表的最后一个节点
if(temp.next==null) {
break;
}
//否则temp=temp的下一个节点
temp=temp.next;
}
//循环出来之后,temp是最后一个节点
temp.next=node;
node.pre=temp;
}
//AddNode2:添加节点,按顺序
public void AddNode2(Node node) {
//因为头结点不能动,所以需要一个辅助节点遍历,找到添加新节点的位置
Node temp=Head;
boolean flag=false; //用于标识链表中是否已经存在新节点的顺序
while(true) {
//如果该节点是最后一个节点,则新节点添加到最后一个位置
if(temp.next==null) {
break;
}else if(temp.next.number>node.number) { //说明找到了添加新节点的位置
break;
}else if(temp.next.number==node.number) { //说明新节点的顺序已经存在在链表中
flag=true;
}
temp=temp.next;
}
if(flag) {
System.out.println("该节点的顺序已经存在,插入失败");
}else {
//则说明新节点在链表中不存在,插入新节点
//新节点的下一个节点=辅助节点的下一个节点
node.next=temp.next;
if(temp.next!=null) { //如果temp的下一个节点不为空,则temp的下一个节点的前一个节点为新节点
temp.next.pre=node;
}
//辅助节点的下一个节点=新节点
temp.next=node;
//新节点的前一个节点为辅助节点
node.pre=temp;
}
}
//删除节点
public void remove(Node node) {
if(Head.next==null) {
System.out.println("链表为空!");
return;
}
//创建辅助节点
Node temp=Head.next;
boolean flag=false; //标识是否找到了要删除的节点
while(true) {
if(temp==null) { //遍历完链表了
break;
}else if(temp.number==node.number) { //找到要删除的节点了
flag=true;
break;
}
temp=temp.next;
}
if(flag) { //链表中存在要删除的节点
temp.pre.next=temp.next; //令temp的前一个节点的下一个节点为temp的后一个节点
if(temp.next!=null) { //如果temp不为最后一个节点的话
temp.next.pre=temp.pre; //令temp的下一个节点的前一个节点为temp的前一个节点
}
}else {
System.out.printf("不存在编号为%d的节点",node.number);
}
}
//修改节点,按照节点的Number来修改
public void update(Node newNode) {
if(Head.next==null) {
System.out.println("链表为空!");
return;
}
//创建辅助节点,对链表遍历,知道找到等于修改节点的number的时候
Node temp=Head.next;
boolean flag=false; //用来标识是否找到了修改节点的Number
while(true) {
if(temp==null) { //则已经遍历完链表
break;
}
if(temp.number==newNode.number) {
flag=true;
break;
}
temp=temp.next;
}
if(flag) {
temp.name=newNode.name;
temp.nickName=newNode.nickName;
}else {
System.out.printf("没有找到编号为%d的节点",newNode.number);
}
}
//展示链表
public void show() {
if(Head.next==null) {
System.out.println("链表为空!");
return;
}
//因为头节点不能动,所以通过辅助节点遍历链表
Node temp=Head.next;
while(true) {
//判断是不是最后一个节点
if(temp.next==null) {
System.out.println(temp);
break;
}
System.out.println(temp);
//temp指向下一个节点
temp=temp.next;
}
}
}
//创建节点
class Node{
public int number;
public String name;
public String nickName;
public Node next; //指向下一个节点
public Node pre;//指向前一个节点
//构造器
public Node(int number,String name,String nickName) {
this.number=number;
this.name=name;
this.nickName=nickName;
}
@Override
public String toString() {
return "Node [number=" + number + ", name=" + name + ", nickName=" + nickName + "]";
}
}
测试代码:
public static void main(String[] args) {
// TODO 自动生成的方法存根
Node node1=new Node(1,"宋江","及时雨");
Node node2=new Node(2,"卢俊义","玉麒麟");
Node node3=new Node(3,"吴用","智多星");
Node node4=new Node(4,"林冲","豹子头");
Node node5=new Node(4,"linchong","豹子头");
//创建一个链表
DoubleLinkedList linkedList=new DoubleLinkedList();
linkedList.AddNode2(node1);
linkedList.AddNode2(node3);
linkedList.AddNode2(node4);
linkedList.AddNode2(node2);
linkedList.show();
System.out.println("------------");
linkedList.remove(node4);
linkedList.show();
}
结果:
Node [number=1, name=宋江, nickName=及时雨]
Node [number=2, name=卢俊义, nickName=玉麒麟]
Node [number=3, name=吴用, nickName=智多星]
Node [number=4, name=林冲, nickName=豹子头]
————————————————————————
Node [number=1, name=宋江, nickName=及时雨]
Node [number=2, name=卢俊义, nickName=玉麒麟]
Node [number=3, name=吴用, nickName=智多星]
来源:https://blog.csdn.net/weixin_43589025/article/details/105884616


猜你喜欢
- 对于yield关键字我们首先看一下msdn的解释:如果你在语句中使用 yield 关键字,则意味着它在其中出现的方法、运算符或 get 访问
- using System.IO;using System.IO.Compression;using System.Web;using Sys
- 之前有做过手机端后台的国际化,因为手机统一传递了language参数所以只要设置LocaleChangeInterceptor就行了/**
- 为了防止用户或者测试MM疯狂的点击某个button,写个方法防止按钮连续点击。具体实例代码如下所示:public class B
- 前言本文将提供一个redis的工具类,可以用在Spring boot以及Spring Cloud项目中,本工具类主要整合了将Redis作为N
- 一维数组1.一维数组的定义方式:int[] array1 = new int[3];//声明创建一个包含3个元素的数组array1(初始值为
- app_main上一篇文章:# Android 10 启动分析之servicemanager篇 (二)在init篇中有提到,init进程会在
- 1. 函数式接口的理解根据重构的思想,需要把容易变化的模块进行抽象并封装起来,从这个点来看,Java8新引入的函数式接口就是基于这个思想进行
- 本文实例讲述了C#文件分割的方法。分享给大家供大家参考。具体如下:1. 小文件分割(适用于小于等于64M的文件):using System;
- 本文实例讲述了C#(asp.net)多线程用法。分享给大家供大家参考,具体如下:using System;using System.Coll
- 什么是链表?链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针连接次序实现的。每一个链表都包含多个节点,
- KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特—莫里斯—普
- Rsa加密RSA是目前最有影响力的公钥加密算法,RSA也是第一个既能用于数据加密也能用于数字签名的算法。该算法基于一个十分简单的数论事实:将
- 本文以实例讲述了C#简单的向量用法,主要包括重载运算符>:以向量长度判断是否为真、重载运算符!=、<、<=等,具体实现代码
- 前言OpenCVSharp是OpenCV的.NET wrapper,是一名日本工程师开发的,项目地址为:https://github.com
- 前几天的一个晚上突然想到微信红包应该有一个随机算法,就自己试着写了下,也不知道对不对,看了看网上的说法,好像到现在为止官方也没有给出一个确切
- 不适用click而用touch自定义监听:class myOnGestureListener extends GestureDetector
- 在Springboot中默认的静态资源路径有:classpath:/METAINF/resources/,classpath:/resour
- 一、前言学习概述:学习四种不同类型的方法应用、方法被调用时的内存图、重载学习目标:熟练掌握方法的应用以及重载二、定义与调用1.概述定义:方法
- foreach 循环 list(map)直接上代码:整体需求就是1.分页对象里面有map map里面又有数组对象2.分页对象里面有list