双向链表

链表是是一种重要的数据结构,有单链表和双向链表之分;本文我将重点阐述不带头结点的双向链表:

不带头结点的带链表

我将对双链表的增加和删除元素操作进行如下解析

1.增加元素(采用尾插法)

(1)链表为空

     新建结点,将头结点first和尾节点last都指向新建结点,尾节点的next指向空。

 

空链表增加元素

(2)链表非空

     先定义一个临时的结点temp保存当前的尾节点,将尾节点last指向新建结点,并将last的prev指向temp,temp的next指向last.

非空链表增加元素

2.删除指定下标的元素

我将分以下三种情况进行讨论

(1)要删除元素为头结点

 用node保存当前头结点first,并将头结点first指向first.next且将现在的first.prev置为空,将node.的next、data分别置为空。

删除头结点

(2)要删除元素为尾节点

      用节点node保存当前的尾节点,将last指向当前尾节点的前一个节点last.prev,并将现last.next置为空,将以前的last即node节点的prev和data置空。

  

删除尾结点

(3)要删除元素为中间节点

用节点node保存要删除的节点,并将要删除节点的前一个节点的next指向要删除节点的下一个节点;要删除节点的下一个节点的prev指向要删除节点的还是那个一个节点;即node.prev. next = node.next;node.next.prev = node.prev。并将要删除节点的prev、next及data置为null.

删除中间结点

  1 package Struct;
2
3 interface Link{
4 void add(Object obj);
5 boolean remove(int index);
6 boolean contain(Object obj);
7 int indexOf(Object obj);
8 boolean set(int index,Object obj);
9 Object get(int index);
10 int length();
11 void clear();
12 Object[] toArray();
13 void printArray(Object[] obj);
14 void printLink();
15 }
16 class Factory{
17 private Factory(){}
18 public static Link getLinkInstance(){
19 return new LinkImpl();
20 }
21 }
22 class LinkImpl implements Link{
23 private Node first;
24 private Node last;
25 private int size;
26 private class Node{
27 private Node prev;
28 private Node next;
29 private Object data;
30 public Node(Object data){
31 this.data = data;
32 }
33 }
34 public void add(Object obj) {
35 //要插入元素为空
36 if(obj == null){
37 return;
38 }
39 Node node = new Node(obj);
40 //空链表
41 if(first == null){
42 first = last = node;
43 first.next = null;
44 size++;
45 }else{
46 //非空链表(尾插)
47 Node temp = this.last;
48 temp.next = node;
49 last = node;
50 last.prev = temp;
51 size++;
52 }
53 }
54 //删除
55 public boolean remove(int index) {
56 //指定下标不合法
57 if(index >= size){
58 return false;
59 }
60 Node node = first;
61 //要删除的节点为头结点
62 if(index == 0){
63 first = node.next;
64 first.prev = null;
65 node.prev = node.next = null;
66 node.data = null;
67 size--;
68 return true;
69 }
70 //要删除节点为尾节点
71 if(index == size-1){
72 Node node1 = last;
73 last = node1.prev;
74 last.next = null;
75 node1.prev = node1.next = null;
76 node1.data = null;
77 size--;
78 return true;
79 }
80 //要删除节点为中间节点
81 Node node3 = get(index);
82 node3.prev.next = node3.next;
83 node3.next.prev = node3.prev;
84 node3.prev = node3.next = null;
85 node3.data = null;
86 size--;
87 return true;
88 }
89 //查看元素是否包含在链表中
90 public boolean contain(Object obj) {
91 //空链表
92 if(first == null&&first.next==null){
93 return false;
94 }
95 for(Node node = first;node!=null;node=node.next){
96 if(node.data==obj){
97 return true;
98 }
99 }
100 return false;
101 }
102 //求取元素obj的下标
103 public int indexOf(Object obj) {
104 Node node = first;
105 int signal = 0;
106 //空链表
107 if(first== null&& first.next == null){
108 return -1;
109 }else{
110 for(node = first;node!=null;node=node.next){
111 if(node.data == obj){
112 return signal;
113 }
114 signal++;
115 }
116 }
117 return signal;
118 }
119 //修改index处的值为obj
120 public boolean set(int index, Object obj) {
121 //指定位置不存在
122 if(index<0||index >= size){
123 return false;
124 }
125 //指定下标超过链表长度
126 if(index >= size){
127 return false;
128 }
129 Node node = first;
130 //若链表头结点是要修改的元素
131 if(node == get(index)){
132 node.data = obj;
133 }
134 Object getObject = get(index);
135 for(node = first;node !=null;node=node.next){
136 if( getObject == node){
137 node.data = obj;
138 }
139 }
140 return true;
141 }
142 //取得index处的元素
143 public Node get(int index) {
144 if(first==null&&first.next==null){
145 return null;
146 }
147 //要查找下标不在范围内
148 if(index >= size){
149 return null;
150 }
151 Node node = first;
152 //要查找元素在中间元素的左侧
153 if(index >=0 && index <= (index<<1)){
154 for(int i = 0;i <= index - 1;i++){
155 if(i == index){
156 return node;
157 }
158 node =node.next;
159 }
160 }
161 else if(index > (index<<1)){
162 //要查找元素在中间元素的右侧
163 for(int i = index; i < size-1;i++){
164 if(i == index){
165 return node;
166 }
167 node = node.next;
168 }
169 }
170 return node;
171 }
172 //求链表长度
173 public int length() {
174 //空链表
175 if(first == null){
176 return 0;
177 }
178 return this.size;
179 }
180 //清空链表
181 public void clear() {
182
183 Node node = first;
184 if(first == null && first.next == null){
185 return;
186 }
187 for(node = first.next;node!=null;){
188 Node temp = node;
189 node.prev = node.next = null;
190 node.data = null;
191 node = node.next;
192 size--;
193 }
194 first.next = null;
195 first.data = null;
196 size--;
197 }
198 //将链表转换成Object数组
199 public Object[] toArray() {
200 //空链表
201 if(first == null && first.next == null){
202 return null;
203 }else{
204 Object[] linkObject = new Object[this.size];//向上转型
205 Node node = first;
206 for(int i = 0;i<size;i++){
207 linkObject[i] = node.data;
208 node = node.next;
209 }
210 return linkObject;
211 }
212 }
213 //打印Object数组
214 public void printArray(Object[] obj){
215 for(int i = 0;i < obj.length;i++){
216 System.out.print(obj[i]+" <-> ");
217 }
218 }
219 //打印链表
220 public void printLink() {
221 Node node = first;
222 for(node = first;node!=null;node=node.next){
223 System.out.print(node.data+" <——> ");
224 }
225 System.out.println();
226 }
227
228 }
229 public class DoubleLinkList {
230 public static void main(String[] args) {
231 Link link = Factory.getLinkInstance();
232 System.out.println("\n"+"=================以下为add测试函数===================");
233 link.add("我是开始位置");
234 link.add("第一名");
235 link.add("第二名");
236 link.add("第三名");
237 link.add("我是结束位置");
238 System.out.println("\n"+"===============以下为printLink测试函数===============");
239 link.printLink();
240 System.out.println("\n"+"===============以下为indexOf测试函数================");
241 System.out.println(link.indexOf("第二名"));
242 System.out.println(link.indexOf("我是结束位置"));
243 System.out.println("\n"+"===============以下为contain测试函数================");
244 System.out.println(link.contain("我是结束位置"));
245 System.out.println(link.contain("hahh"));
246 System.out.println("\n"+"===============以下为get测试函数================");
247 System.out.println(link.get(0));
248 System.out.println(link.get(4));
249 System.out.println(link.get(2));
250 System.out.println(link.get(8));
251 System.out.println("\n"+"===============以下为length测试函数================");
252 System.out.println(link.length());
253 System.out.println("\n"+"===============以下为set测试函数===================");
254 System.out.println(link.set(0, "我是特等奖"));
255 link.printLink();
256 System.out.println("\n"+"===============以下为toArray测试函数===================");
257 Object[] linkObj = link.toArray();
258 System.out.println("\n"+"===============以下为printArray测试函数===================");
259 link.printArray(linkObj);
260 System.out.println("\n"+"===============以下为remove测试函数===================");
261 //删除尾节点
262 System.out.println(link.remove(4));
263 link.printLink();
264 //删除头结点
265 System.out.println(link.remove(0));
266 link.printLink();
267 //删除中间节点
268 System.out.println(link.remove(1));
269 link.printLink();
270 System.out.println(link.length());
271 System.out.println("\n"+"===============以下为clear测试函数===================");
272 link.clear();
273 System.out.println(link.length());
274 }
275 }

测试结果:

双向链表——Java实现的更多相关文章

  1. 线性链表的双向链表——java实现

    .线性表链式存储结构:将采用一组地址的任意的存储单元存放线性表中的数据元素. 链表又可分为: 单链表:每个节点只保留一个引用,该引用指向当前节点的下一个节点,没有引用指向头结点,尾节点的next引用为 ...

  2. 双向链表--Java实现

    /*双向链表特点: *1.每个节点含有两个引用,previos和next,支持向前或向后的遍历(除头节点) *2.缺点插入或删除的时候涉及到引用修改的比较多 *注意:下面的双向链表其实也实现了双端链表 ...

  3. 双向链表-java完全解析

    原文:https://blog.csdn.net/nzfxx/article/details/51728516 "双向链表"-数据结构算法-之通俗易懂,完全解析 1.概念的引入 相 ...

  4. 剑指Offer:面试题27——二叉搜索树与双向链表(java实现)

    问题描述: 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表.要求不能创建任何新的结点,只能调整树中结点指针的指向. 思路: 将树分为三部分:左子树,根结点,右子树. 1.我们要把根结点与左 ...

  5. 双向链表JAVA代码

      //双向链表类 publicclassDoubleLinkList{       //结点类     publicclassNode{           publicObject data;   ...

  6. LRU hashMap(拉链) + 双向链表 java实现

    //基于 hash (拉链法) + 双向链表,LRUcache //若改为开放寻址,线性探测法能更好使用cpuCache public class LRU { private class Node { ...

  7. 《剑指offer》面试题27 二叉搜索树与双向链表 Java版

    (将BST改成排序的双向链表.) 我的方法一:根据BST的性质,如果我们中序遍历BST,将会得到一个从小到大排序的序列.如果我们将包含这些数字的节点连接起来,就形成了一个链表,形成双向链表也很简单.关 ...

  8. Spark案例分析

    一.需求:计算网页访问量前三名 import org.apache.spark.rdd.RDD import org.apache.spark.{SparkConf, SparkContext} /* ...

  9. JAVA单向/双向链表的实现

    一.JAVA单向链表的操作(增加节点.查找节点.删除节点) class Link { // 链表类 class Node { // 保存每一个节点,此处为了方便直接定义成内部类 private Str ...

随机推荐

  1. shell 脚本控制命令的执行顺序

    &&,||,(),{},& 五个符号的运用shell脚本执行命令的时候,有时候会依赖于前一个命令是否执行成功.而&&和||就是用来判断前一个命令执行效果的. 也 ...

  2. Centos7 升级过内核 boot分区无法挂载修

    参考连接:https://www.cnblogs.com/heqiuyong/p/11186301.html 故障图 挂载系统盘,光盘启动,急救模式, chroot /mnt/sysimage 报错 ...

  3. 完美解决Github网页打开超慢的问题

    由于某些原因,国内访问Github会异常缓慢,在clone仓库时甚至只有10k以下的速度,下载半天有时还会失败需要从头再来,甚是让人恼火.本文介绍通过修改系统hosts文件的办法,绕过国内dns解析, ...

  4. C# 计算农历日期方法(2021版)

    解决问题 旧版农历获取方法报错,会有 到 2021年 m数组越界了 if (LunarData[m] < 4095) 此方法可以解决 主体代码 public static class China ...

  5. Django 小实例S1 简易学生选课管理系统 4 实现登录页面

    Django 小实例S1 简易学生选课管理系统 第4节--实现登录页面 点击查看教程总目录 作者自我介绍:b站小UP主,时常直播编程+红警三,python1对1辅导老师. 本文涉及到的新的额外知识点: ...

  6. 编译使用nginx

    nginx-1.18.0 ./configure --prefix=$HOME/nginx --with-http_ssl_module make -j32; make install [fangju ...

  7. C语言通过指针数组和二维数组读取文件

    1 # include <stdio.h> 2 # include <stdlib.h> 3 # include <time.h> 4 # include < ...

  8. [Net 6 AspNetCore Bug] 解决返回IAsyncEnumerable<T>类型时抛出的OperationCanceledException会被AspNetCore 框架吞掉的Bug

    记录一个我认为是Net6 Aspnetcore 框架的一个Bug Bug描述 在 Net6 的apsnecore项目中, 如果我们(满足以下所有条件) api的返回类型是IAsyncEnumerabl ...

  9. mabatis的sql标签

    定义:mapper.xml映射文件中定义了操作数据库的sql,并且提供了各种标签方法实现动态拼接sql.每个sql是一个statement,映射文件是mybatis的核心. 一,内容标签 1.Name ...

  10. Java编程之学习技巧

    **本人博客网站 **IT小神 www.itxiaoshen.com 找到技术点 首先得知道自己要学习技术是什么?不管是来自同事.技术大牛推荐还是通过搜索引擎得到,或者另有出处如.技术交流群.技术论坛 ...