链表---双向链表的解析与实现

来源:互联网 发布:精通qt4编程 源码 编辑:程序博客网 时间:2024/06/04 23:20

(1)如果为每个节点保留两个引用prvenext,prev指向当前节点的上一个节点,让next指向当前节点的下一个节点。此时链表既可以向前依次访问每个节点,也可以向后依次访问每个节点,这种形式的节点称为双向链表。

(2)双向链表的查找

   因为双向链表既可以向前搜索也可以向后搜索,当被搜索节点更靠近head或者tail中的某一端时,就从那一端开始搜索index<size/2head开始搜索,index>size/2tail开始搜索

(3)双向链表的插入


(4)双向链表的删除


实现

public class DoubleLinkedList<T>{//节点类  private class Node  {  //每个节点有三个成员变量   private T data;  private Node next;  private Node prev;  public Node()  {}  public Node(T data,Node next,Node prev)  {  this.data = data;  this.next = next;  this.prev = prev;  }  }  //分别用来指向链表的头节点、尾节点、保存链表的长度  private Node head;  private Node tail;  private int size;    //链表的构造函数   public DoubleLinkedList()  {  head = null;  tail = null;  }  public DoubleLinkedList(T element)  {  head = new Node(element,null,null);  tail = head;  size++;  }      //链表的长度  public int length()  {  return size;  }  //查找指定索引处的节点  private Node getNodeByIndex(int index)  { if(index < 0 || index > size-1) { throw new IndexOutOfBoundsException("双向链表索引越界"); } if(index < size / 2)//如果索引在前半段的位置则从头节点开始遍历 { Node current = head; for (int i = 0; i < size / 2 && current != null; i++,current = current.next){if(i == index){return current;}} } else { Node current = tail; for (int i = size-1; i > size / 2 && current!= null; i++,current = current.prev){if(i == index ){return current;}} }return null;  }    //查找指定元素的索引位置  public int  locateIndexByElement(T element)  {  Node current = head;  for (int i = 0; i < size && current != null; i++,current = current.next){if(current.data == element){return i;}}  return -1;  }    //插入 将指定的元素插入到指定的位置处  public void insert(T element,int index)  {  if(index < 0 || index > size )  {  throw new IndexOutOfBoundsException("双向链表插入索引越界");  }    if(null == head)  {add(element);   }  else  {  if(index == 0)  {  addAtHead(element);  }  else  {  Node prev = getNodeByIndex(index-1);//获取要出入位置的前一个节点  Node next = prev.next;//第index位置的节点将会变为新节点的下一个节点  Node newNode = new Node(element,next,prev);//新节点的前一个节点是prev 后一个节点是next   prev.next = newNode;   next.prev = newNode;   size++;  }  }  }  //插入  尾差法  public void  add(T element)  {  if (head == null)  { addAtHead(element);  }  else  {Node newNode = new Node(element,null,tail);tail.next = newNode;tail = newNode;  }  size++;  }   //插入 头差法  public void addAtHead(T element)  {    Node newNode = new Node(element,head,null);    if(head==null)    {  head = newNode;  tail = head;    }    else    {  head.prev = newNode;  head = newNode;    }    size++;  }    //删除  public T delete(int index)  {  if(index < 0 || index > size)  {  throw new IndexOutOfBoundsException("双向链表插入索引越界");  } Node deleteNode;  if(index == 0)//若是删除第一个节点 要重新得到头节点  {  deleteNode = head;  head = head.next;//新的头节点的是原来头节点的下一个节点  deleteNode.next = null;  } else{Node prev = getNodeByIndex(index-1);//找到要删除节点的前一个节点deleteNode = prev.next;//找到要删除的节点prev.next = deleteNode.next;//把prev的next指向要删除节点的下一个节点if(deleteNode.next != null){deleteNode.next.prev = prev;//要删除节点的下一个节点指向的前一个节点是prev}deleteNode.prev = null;deleteNode.next = null;}     size--;    return deleteNode.data;      }  //判断链表是否为空  public boolean isEmpty()  {  return size == 0;  }    //清空线性变    public void clear()  {  head = null;  tail = null;  size = 0;  }    public String toString()  {  if(isEmpty())  {  return "[]";  }  else  {  StringBuilder sb = new StringBuilder("[");  for ( Node current = head;current != null; current = current.next) {sb.append(current.data.toString() + ","); } int len = sb.length(); return sb.delete(len-1,len).append("]").toString();  }  }  }
测试

public class DoubleLlinkedListTest{public static void main(String[] args){DoubleLinkedList<String> list = new DoubleLinkedList<String>();list.addAtHead("HELLO");list.add("world");System.out.println(list);list.insert("111",1);list.insert("222",1);System.out.println(list);list.addAtHead("head"); System.out.println(list);list.delete(2);System.out.println(list);list.clear();System.out.println(list );}}
结果

[HELLO,world]
[HELLO,222,111,world]
[head,HELLO,222,111,world]
[head,HELLO,111,world]
[]


0 0