(3)双向链表(Java)
2014-04-14 13:43
323 查看
双向链表中每个节点保留两个引用prev和next,让prev指向当前节点的上一个节点,让next指向当前节点的下一个节点,此时的链表既可以向后一次访问每个节点,也可以依次访问每个节点,也可以向前一次访问每个节点。
操作:
①查找:即可从头结点开始搜索,也可以从尾节点开始搜索,取决于被搜索的节点是更靠近header还是更靠近tail,用index<size/2判断,靠近哪个就从哪边开始搜索。
②插入:插入一个节点必须同时修改两个方向的节点。
③删除:删除一个节点也需要同时修改两个方向的节点
因为双向链表需要维护两个方向的指针,因此程序在添加节点、删除节点都比维护普通单链表更复杂。
一个双向链表的实现如下:
操作:
①查找:即可从头结点开始搜索,也可以从尾节点开始搜索,取决于被搜索的节点是更靠近header还是更靠近tail,用index<size/2判断,靠近哪个就从哪边开始搜索。
②插入:插入一个节点必须同时修改两个方向的节点。
③删除:删除一个节点也需要同时修改两个方向的节点
因为双向链表需要维护两个方向的指针,因此程序在添加节点、删除节点都比维护普通单链表更复杂。
一个双向链表的实现如下:
package com.xuan.datastructs; public class DuLinkList<T> { //定义一个内部类Node,Node实例代表链表的节点 private class Node{ //保存节点的数据 private T data; //指向上个节点的引用 private Node prev; //指向下个节点的引用 private Node next; //无参数的构造器 public Node() { } //初始化全部属性的构造器 public Node(T data,Node prev,Node next){ this.data=data; this.prev=prev; this.next=next; } } //保存该链表的头节点 private Node header; //保存该链表的尾节点 private Node tail; //保存该链表中已经包含的节点数 private int size; //创建空链表 public DuLinkList() { //空链表,header和tail都是null header=null; tail=null; } //以指定数据元素来创建链表,该链表只有一个元素 public DuLinkList(T element){ header=new Node(element,null,null); //只有一个节点,header、tail都指向该节点 tail=header; size++; } //返回链表的长度 public int length(){ return size; } //获取链式线性表中索引为index处的元素 public T get(int index){ return getNodeByIndex(index).data; } //根据索引index获取指定位置的节点 private Node getNodeByIndex(int index) { if(index<0||index>size-1){ throw new IndexOutOfBoundsException("线性表索引越界"); } if(index<=size/2){ //从header节点开始 Node current=header; for (int i = 0; i <= size/2&¤t!=null; i++,current=current.next) { if(i==index){ return current; } } }else{ //从tail节点开始搜索 Node current=tail; for (int i = size-1; i >size/2&¤t!=null; i++,current=current.prev) { if(i==index){ return current; } } } return null; } //查找链式线性表中指定元素的索引 public int locate(T element){ //从头节点开始搜索 Node current=header; for(int i=0;i<size&¤t!=null;i++,current=current.next){ if(current.data.equals(element)){ return i; } } return -1; } //向线性链式表的指定位置插入一个元素 public void insert(T element,int index){ if(index<0||index>size){ throw new IndexOutOfBoundsException("线性表索引越界"); } //如果还是空链表 if(header==null){ add(element); }else{ //当index为0时,在链表头部插入 if(index==0){ addAtHeader(element); }else{ //获取插入点的前一个节点 Node prev=getNodeByIndex(index-1); //获取插入点的节点 Node next=prev.next; //让新节点的next引用指向next节点,prev引用指向prev节点 Node newNode=new Node(element,prev,next); //让prev的next指向新节点 prev.next=newNode; //让prev的下一个节点的prev指向新节点 next.prev=newNode; size++; } } } //采用尾插法为链表添加新节点 public void add(T element){ //若该链表还是空链表 if(header==null){ header=new Node(element,null,null); //只有一个节点,header、tail都指向该节点 tail=header; }else{ //创建新节点,新节点的pre指向原tail节点 Node newNode=new Node(element,tail,null); //让尾节点的next指向新增的节点 tail.next=newNode; //以新节点作为新的尾节点 tail=newNode; } size++; } //采用头插法为链表添加新节点 public void addAtHeader(T element){ //创建新节点,让新节点的next指向原来的header,并以新节点作为 header=new Node(element,null,header); //如果插入之前是空链表 if(tail==null){ tail=header; } size++; } //删除链式线性表中指定索引处的元素,返回删除节点处的元素 public T delete(int index){ if(index<0||index>size-1){ throw new IndexOutOfBoundsException("线性表索引越界"); } Node del=null; //如果被删除的是header节点 if(index==0){ del=header; header=header.next; //释放新的header节点的prev引用 header.prev=null; }else{ //获取删除点的前一个节点 Node prev=getNodeByIndex(index-1); //获取将要被删除的节点 del=prev.next; //让被删除节点的next指向被删除节点的下一个节点 prev.next=del.next; if(del.next!=null){ del.next.prev=prev; } //将被删除节点的prev、next引用赋为null del.prev=null; del.next=null; } size--; return del.data; } //删除链式线性表中最后一个元素 public T remove(){ return delete(size-1); } //判断链式线性表是否为空链表 public boolean empty(){ return size==0; } //清空线性表 public void clear(){ //将底层数组所有元素赋为null header=null; tail=null; size=0; } public String toString(){ //链表为空链表 if(empty()){ return "[]"; }else{ StringBuilder sb=new StringBuilder("["); for(Node current=header;current!=null;current=current.next){ sb.append(current.data.toString()+", "); } int len=sb.length(); return sb.delete(len-2, len).append("]").toString(); } } public String reverseToString(){ //链表为空链表时 if(empty()){ return "[]"; }else{ StringBuilder sb=new StringBuilder("["); for(Node current=tail;current!=null;current=current.prev){ sb.append(current.data.toString()+", "); } int len=sb.length(); return sb.delete(len-2, len).append("]").toString(); } } //测试 public static void main(String[] args) { DuLinkList<String> list=new DuLinkList<String>(); list.insert("a", 0); list.add("b"); list.insert("c", 0); //在索引为1处插入一个新元素 list.insert("d", 1); //输出顺序线性表的元素 System.out.println(list); //删除索引为2处的元素 list.delete(2); System.out.println(list); System.out.println(list.reverseToString()); //获取c字符串在顺序线性表中的位置 System.out.println("c在顺序线性表中位置:"+list.locate("c")); System.out.println("链表中索引1处的元素:"+list.get(1)); list.remove(); System.out.println("调用remove方法后的链表:"+list); list.delete(0); System.out.println("调用delete(0)方法后的链表:"+list); } }
相关文章推荐
- 剑指Offer:面试题27——二叉搜索树与双向链表(java实现)
- 二叉搜素树与双向链表(java版)
- 双向链表Java实现
- 双向链表java实现
- 数据结构基础java实现—双向链表
- java基础之面试篇四-单向链表和双向链表区别
- 数据结构--双向链表实现(java)
- java集合—— 链表(java中的所有链表都是双向链表)
- java数据结构与算法-双向链表
- 数据结构与算法Java版——双向链表
- java实现双向链表操作
- 大话数据结构(四)——双向链表的java实现
- java实现双向链表
- 数据结构-双向链表(一)(java)
- 常见算法-将二叉搜索树转化为排序的双向链表(java版)
- 二叉搜索树与双向链表java实现
- 《链表》——单向链表和双向链表(Java)
- java数据结构 四(双向链表)
- 双向链表(LinkedList) java实现
- 双向链表 --java实现