双向链表、双端(双向)链表、循环(双向)链表示意(简)图:

声明下面各图中,箭头指向的是整个节点,而不是指向节点中的prior或next。

双向链表:只有一个指针指向最开始的结点。

双端(双向)链表:有两个指针分别指向两端的节点。

循环(双向)链表:指向形成一个闭环。

双端(双向)链表的Java实现(简单示例):

注:双向链表、双端(双向)链表、循环(双向)链表的实现思路几乎一样,这里以实现双端(双向)链表示例。

/*** 双端(双向)链表的(简单)实现** @author JustryDeng* @date 2019/5/21 20:51*/
public class DoublesidedLinkedlistImpl<T>  {/** 节点的个数 */private int size;/*** 尾节点* 注:本人新增节点时,从尾巴上新增* 注:也可以从头上进行新增节点*/private Node rear;/*** 当前节点* 即:链表中最前面的节点,可理解为 队列中的头结点*/private Node head;/*** 成员内部类, 节点*/private class Node {/** 内部类的元素,Object类型 */private T data;/** 上一个节点(即:前驱节点)的地址 */private Node prior;/** 下一个节点(即:后继节点)的地址 */private Node next;private Node(T data) {this.data = data;}public T getData() {return data;}public void setData(T data) {this.data = data;}public Node getPrior() {return prior;}public void setPrior(Node prior) {this.prior = prior;}public Node getNext() {return next;}public void setNext(Node next) {this.next = next;}}/*** 新增节点** @param obj*         添加的元素* @return  添加的元素对应的节点* @date 2019/5/20 20:48*/public Node addNode(T obj) {// obj不能为nullnotNullCheck(obj);// 每次增加的元素,都作为新的尾节点Node newRear = new Node(obj);if (size == 0) {head = newRear;rear = newRear;} else {newRear.prior = rear;rear.next = newRear;// 更新尾节点rear = rear.next;}size++;return newRear;}/*** 删除当前(头)节点** @return  被删除了的(头)节点* @date 2019/5/20 20:50*/public Node deleteHead() {if(isEmpty()) {return null;}// targetObj存放原来的头节点数据Node targetNode = head;if (head.next != null) {// 断开后继节点对要删除的节点的引用head.next.prior = null;}// 更新头节点head = head.next;size--;return targetNode;}/*** 删除指定元素对应的第一个节点** @return  删除成功与否(若元素不存在,则返回false)* @date 2019/5/20 20:50*/public boolean deleteFirstNode(T obj) {// obj不能为nullnotNullCheck(obj);// 当head未null时,说明,当前为空链表if (size == 0) {return false;}// 当前节点Node current = head;// 前驱节点Node previous = head;// 判断条件,如果当前节点的值和待删除的值不一致,则继续while (!obj.equals(current.data)) {// 如果下一个节点不存在(即:当前节点是尾节点)// 则说明,不存在 元素值为obj的节点,直接返回falseif (current.next == null) {return false;} else {// 更新前驱节点、当前节点previous = current;current = current.next;}}// 如果要删除的节点是第一个节点;if (head.equals(current)) {if (head.next != null) {// 断开后继节点对要删除的节点的引用head.next.prior = null;}// 更新头结点head = current.next;// 如果要删除的节点是尾节点} else if ((rear.equals(current))) {// 前驱节点断开对要删除的节点的应用previous.next = null;// 如果要删除的节点不是头结点(是中间的某个节点或尾节点)} else {// 将当前节点“抠除”,并将“两端”接上previous.next = current.next;current.prior = previous;}size--;return true;}/*** 删除指定元素对应的所有节点* 注:此方法性能较低,少用或不用*** @return  删除了的节点数* @date 2019/5/20 20:50*/public int deleteAllNode(T obj) {int count = 0;while(deleteFirstNode(obj)){count++;}return count;}/*** 查找元素的(第一个)节点** @param obj*         待查找的元素对象* @return 元素的(第一个)节点, 无则返回null*/public Node find(T obj) {// obj不能为nullnotNullCheck(obj);Node currNode = head;// 临时大小为sizeint tempSize = size;while (tempSize > 0) {if (obj.equals(currNode.data)) {return currNode;} else {currNode = currNode.next;}tempSize--;}return null;}/*** 非空检验** @param obj*            被验证的对象* @throws NullPointerException 空指针异常(运行时异常)* @date 2019/5/20 21:00*/private void notNullCheck(T obj){if(obj == null) {throw new NullPointerException("data must not be null!");}}/*** 判断链表是否为空** @return  链表是否为空* @date 2019/5/20 20:49*/public boolean isEmpty() {return size == 0;}@Overridepublic String toString() {if (isEmpty()) {return "[]";}StringBuilder sb = new StringBuilder(16);sb.append("[");Node currentNode = head;for (int i = 0; i < size; i++) {sb.append(currentNode.data);sb.append(", ");currentNode = currentNode.next;}int length = sb.length();sb.delete(length - 2, length).append("]");return sb.toString();}public static void main(String[] args) {DoublesidedLinkedlistImpl<String> uli = new DoublesidedLinkedlistImpl<>();// 增uli.addNode("A");uli.addNode("B");uli.addNode("C");uli.addNode("C");uli.addNode("D");uli.addNode("C");uli.addNode("E");uli.addNode("E");uli.addNode("F");uli.addNode("E");// toStringSystem.out.println("增加节点后的初始化链表:\t" + uli);// 找到C元素对应的第一个节点System.out.println("找到C元素对应的第一个节点:" + uli.find("C")+ ",该节点的下下个节点的数据内容为:"+ uli.find("C").getNext().getNext().getData());// 删除头结点uli.deleteHead();// toStringSystem.out.println("删除头结点后:\t" + uli);// 删除C元素对应的第一个节点uli.deleteFirstNode("C");// toStringSystem.out.println("删除C元素对应的第一个节点后:\t" +uli);// 删除E元素对应的所有节点uli.deleteAllNode("E");// toStringSystem.out.println("删除E元素对应的所有节点后:\t" +uli);}
}

测试一下:

运行(写在实现类里面的)主方法,控制台输出:

由此可见:简单的双端(双向)链表实现完毕!

^_^ 如有不当之处,欢迎指正

^_^ 学习视频
               51CTO学院《数据结构与算法》,讲师张晨光

^_^ 本文已被收录进《程序员成长笔记(五)》,笔者JustryDeng

【数据结构】之双向链表、双端(双向)链表、循环(双向)链表相关推荐

  1. 《恋上数据结构第1季》队列、双端队列、循环队列、循环双端队列

    队列(Queue) 队列 Queue 队列的接口设计 队列源码 双端队列 Deque 双端队列接口设计 双端队列源码 循环队列 Circle Queue 循环队列实现 索引映射封装 循环队列 – %运 ...

  2. 2021 - 9 -下旬 数据结构- 线性表 -双端循环队列 - java实现

    //循环双端队列:Circle Double Ended Queue //本质是对动态数组的优化 //队头队尾都可以添加或删除元素 //相比于普通循环队列需要注意的点是在队头插入元素时的对front前 ...

  3. 经典数据结构和算法 双端队列 java

    选一个简单的数据结构聊一聊,话说有很多数据结构都在玩组合拳,比如说:块状链表,块状数组,当然还有本篇的双端队列,是的,它就是 栈和队列的组合体. 一:概念 我们知道普通队列是限制级的一端进,另一端出的 ...

  4. 【python】数据结构与算法—双端队列(二)

    一.双端队列的特点: 可以对两端进行操作:队尾入队,队首出队:队尾出队,队首入队: 二.双端队列要实现的操作: 三.代码块(链表实现) class Node():def __init__(self,d ...

  5. 数据结构--队列、双端队列实际举例详解(Python代码)

    https://blog.csdn.net/hanhanwanghaha宝藏女孩 欢迎您的关注! 欢迎关注微信公众号:宝藏女孩的成长日记 让这个可爱的宝藏女孩在努力的道路上与你一起同行! 如有转载,请 ...

  6. 【python】数据结构与算法—双端队列(一)

    一.双端队列的特点: 可以对两端进行操作:队尾入队,队首出队:队尾出队,队首入队: 二.双端队列要实现的操作: 三.代码块(顺序表实现): class Deque:def __init__(self) ...

  7. 双向非循环递增链表——插入,删除,清空

    #include <stdio.h> #include <malloc.h> #include <stdlib.h> #include <string.h&g ...

  8. Proj1a 数据结构:双端队列| CS61B-Spring-2018

    主要任务 编写双端队列,能够addFirst, remove First, addLast, removeLast.并实现其他一些辅助功能. 使用两种数据结构来完成双端队列,分别是链表和数组. 要求这 ...

  9. C++数据结构和算法2 栈 双端/队列 冒泡选择插入归并快排 二三分查找 二叉树 二叉搜索树 贪婪 分治 动态规划

    C++数据结构和算法2 栈 双端/队列 冒泡选择插入归并快排 二三分查找 二叉树 二叉搜索树 贪婪 分治 动态规划 博文末尾支持二维码赞赏哦 _ github 章3 Stack栈 和 队列Queue= ...

  10. apriori算法c++实现_经典数据结构与算法(四):Python/C/C ++实现队列类型双端队列数据结构...

    前期文章点击这里: 经典数据结构与算法(一):Python/C/C ++实现堆栈和队列 双端队列或双端队列是一种队列,其中可以从前面或后面执行元素的插入和删除.因此,它不遵循FIFO规则(先进先出). ...

最新文章

  1. Python 中print 和return 的区别
  2. 多线程解决同步问题浅析
  3. 守护进程-----杀死自己的进程再重新启动自己
  4. HDU1426(DFS)
  5. python文件的路径_python3 文件及文件夹路径相关
  6. 电子书格式如何相互转换ePub、Azw3、Mobi、Doc、PDF、TXT
  7. Masscan教程和入门手册
  8. 分析 : BSOD案例 2013-0821
  9. Web导出Excel总结
  10. 关于majaro安装后的配置,简单记录 机型华硕FZ53v
  11. python如何限制字符串长度_python如何修改字符串长度
  12. 学经济还是学计算机,经济学,计算机和人生
  13. 硬件中常说的EMC是啥?
  14. 【drawio笔记】向ERD表,列表和UML类添加行
  15. mysql查询性别语句_MySQL查询语句简单操作示例
  16. 网易企业邮箱申请,申请企业邮箱流程分享~
  17. 2022-2027年中国农村网络零售行业市场深度分析及投资战略规划报告
  18. OpenCV分离图像通道
  19. 阿米巴管理 在软件企业中的问题
  20. web前端登录密码保存业务

热门文章

  1. 谷歌中国搜索业务再遇挑战
  2. 产业融合下的商帮:思科与惠普
  3. MOBA游戏学会这些知识,你才算真的入门了!
  4. 三体 黑暗森林法则
  5. 感遇十二首·其四。唐朝,张九龄
  6. javaweb开发微信公众号项目中怎么使用WEUI
  7. 怎样将CDR文件转换为PS分图层文件
  8. 使用VUE实现在table中文字信息超过5个隐藏,鼠标移到时弹窗显示全部
  9. 强大的安卓手机远程管理工具 – Droidjack
  10. Visual Studio软件中的行号设置