数据结构之双链表
来源:互联网 发布:acdsee软件 编辑:程序博客网 时间:2024/05/18 02:54
在单链表分析中,每个结点只有一个指向后继结点的next域,如果此时已知当前结点,需要查找其前驱结点,那么必须从head头指针遍历至p的前驱结点,操作效率很低,因此如果p指向前驱结点的next的域,效率就会提升很多,因此就出现了双链表。
双链表是链表的一种。它由结点组成,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双链表的任意一个结点开始,都可以很方便的访问他的前驱结点和后继结点。
双链表的结点示意图如下:
双链表的示意图如下:
双链表的插入操作分析
双链表的插入一般分为三种情况:
1)插入空双链表
2)插入双链表的尾部
3)双链表的中间插入
从上图可以看出第一种和第二种情况实际属于一种情况,只需要注意front.next != null 的情况而第三种情况就不需要注意这种情况,因为在中间插入的时候无论何时它的后继结点都不会为空。
插入操作实际上就是把原来的链接打断,然后把前一个结点的next域指向先插入节点的pre域,将新插入的结点next域指向后一个结点的pre域。
双链表删除操作分析
双链表的删除操作也分为两种情况:
1)双链表的尾部删除操作
2)双链表的中间结点删除操作
第一种情况只要注意p.next.pre抛空指针的情况,而对于第二种情况不需要关心。
双链表的删除操作实际就是把要删除结点p的pre域和next域都断开,然后把p前后的结点连接在一起。
双链表的查询分析:
双链表的查询操作与单链表的查询操作相似,只需要查找的当前结点获取他的data即可。
循环双链表就是双链表的最后一个结点的next域指向头结点,而头结点的prev指针指向最后一个结点。
在循环双链表中我们不再需要尾指向结点,因为整个链表已构成循环,在头结点head的位置也可以轻松获取到尾部结点的位置。对于循环双链表的插入、删除操作也无需区分位置操作的情况,这是由于循环双链表的本身的特殊性,使p.next.pre永远不可能为null,因此我们在插入和删除时代码实现相对简单些。
用 java 实现链表如下:
Step1.定义结点
package test;/** * Created by DELL on 2017/12/1. */public class Dnode<T> { public T data; public Dnode<T> prev;//前继指针 public Dnode<T> next;//后继指针 public Dnode(T data, Dnode<T> prev, Dnode<T> next){ this.data = data; this.next = next; this.prev = prev; } public Dnode(T data){ this(data,null,null); } public Dnode(){ this(null,null,null); } public String toString(){ return this.data.toString(); }}
Step2.定义一个双链表
package test;/** * Created by DELL on 2017/12/1. */public class DoubleLinkedList<T> { private Dnode<T> head ;//不带数据的头结点 private int size;//链表的大小 public DoubleLinkedList() { head = new Dnode<>(null,null,null); head.prev = head.next = head; size = 0; } //返回结点数目 public int count(){ return size; } //返回链表是否为空 public boolean isEmpty(){ return size == 0; } //获取第index位置的结点 public Dnode<T> getNode(int index){ if(index<0 || index >= size){ throw new IndexOutOfBoundsException(); } //正向查找 if(index <= size/2){ Dnode<T> node = head.next; for(int i=0;i < index; i++){ node = node.next; } return node; } //反向查找 Dnode<T> rnode = head.next; int rindex = size - index - 1; for(int j=0;j<index;j++){ rnode = rnode.prev; } return rnode; } //获取第index位置的结点的值 public T get (int index){ return getNode(index).data; } //获取第一个结点的值 public T getFirst(){ return getNode(0).data; } //获取最后一个结点的值 public T getLast(){ return getNode(size-1).data; } //将结点插入插入到第index位置之前 public void insert(int index , T t){ if(index == 0){ Dnode<T> node = new Dnode<T>(t,head,head.next); //让head的后继结点的prev域指向新插入的结点 head.next.prev = node; head.next = node; //链表长度加1 size ++ ; return ; } //获得该位置的结点 Dnode<T> inode = getNode(index); //定义一个新插入的结点 Dnode<T> tnode = new Dnode<T>(t, inode.prev, inode); //让该位置上的结点的前继结点的next域指向新插入的结点 inode. prev.next = tnode; inode.next = tnode; size++; return ; } //将结点插入到第一个结点处 public void insertFist(T t){ insert(0,t); } //将结点追加到链表的末尾 public void insertLast(T t){ Dnode dnode = new Dnode<T>(t,head.prev,head); //head的前继结点就是链表的尾结点 head.prev.next = dnode; head.prev = dnode; size++; } //删除index位置的节点 public void del(int index){ Dnode<T> inode = getNode(index); //该位置上的结点的前继结点的next域指向该位置结点的后继结点 inode.prev.next = inode.next; //该位置上的结点的后继结点的prev域指向该位置结点的前继结点 inode.next.prev = inode.prev; inode = null; size -- ; } //删除第一个结点 public void delFist(){ del(0); } //删除最后一个结点 public void delLast(){ del(size-1); } public static void main (String[] args){ System.out.println("链表的插入操作"); int[] array = {10,20,30,40}; //创建双链表 DoubleLinkedList<Integer> doubleLinkedList = new DoubleLinkedList<>(); doubleLinkedList.insert(0,20);//将20插入到第一个位置 doubleLinkedList.insertLast(10);//将10插入到链表末尾 doubleLinkedList.insertFist(30);//将30插入链表的第一个位置 for(int i=0;i<doubleLinkedList.size;i++){ //输出链表的值 System.out.println(doubleLinkedList.get(i)); } System.out.println("链表的大小为:"+doubleLinkedList.count()); System.out.println("…………………………………………………………"); System.out.println("链表的查找操作"); System.out.println("获取第一个结点的值:"+doubleLinkedList.getFirst()); System.out.println("获取最后一个结点的值:"+doubleLinkedList.getLast()); System.out.println("获取任意结点的值:"+doubleLinkedList.getNode(2)); System.out.println("………………………………………………………………"); System.out.println("链表的删除操作"); System.out.println("删除第一个结点后的链表的值"); doubleLinkedList.delFist(); for(int i=0;i<doubleLinkedList.size;i++){ //输出链表的值 System.out.println(doubleLinkedList.get(i)); } //其他的删除方法类似,直接调用即可。 }}
- 数据结构学习之双链表
- 数据结构之双链表
- 数据结构之双链表
- 数据结构之双链表
- 数据结构之双链表
- 数据结构之双链表
- 数据结构之双链表
- 数据结构之双链表
- 数据结构基础 之 双链表
- 数据结构之双链表
- 数据结构之双链表操作
- 数据结构学习之双链表
- 数据结构之双链表
- 数据结构之双链表
- java数据结构之循环双链表
- 数据结构之单链表与双链表
- 数据结构之线性结构(双链表)【四】
- 数据结构之双链表C++(模板)
- 【BDTC 2017讲师专访】张伟博士:阿里巴巴百亿级别的三元组知识图谱掌舵者
- windows下Python、pip、pyspider的安装,构建爬虫环境(二)
- 多线程-单例下线程安全验证
- 使用GNURadio和RTL-SDR搭建FM广播接收机
- 安卓相关的开源项目和控件网址
- 数据结构之双链表
- c++输出当前时间
- 大型网站技术架构(三)——架构核心要素
- 如何使用CNN推理机在IoT设备上实现深度学习
- C#语言笔试题
- codev的小程序
- word 转化为HTML
- JavaScript的理解01
- OSI七层与TCP/IP五层网络架构详解