大话数据结构五:线性表的链式存储结构(双向链表)

1. 双向链表:在单链表的每个结点中,再设置一个指向其前驱结点的指针域,那么在双向链表中的结点都有两个指针域,一个指向直接后继,另一个指向直接前驱。


2. 单链表和双向链表比较:

单链表:总是要从头到尾找结点,只能正遍历,不能反遍历。

双向链表: 可以从头找到尾,也可以从尾找到头,即正反遍历都可以,可以有效提高算法的时间性能,但由于每个结点需要记录两份指针,所以在空间占用上略多一点,这就是通过空间来换时间。


3. Java实现双向链表:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. // 双向链表  
  2. public class DoubleLinkedList<E> {  
  3.     private Node<E> head; // 头结点  
  4.     private int size; // 链表长度  
  5.   
  6.     // 建立一个空链表  
  7.     public DoubleLinkedList() {  
  8.         head = null;  
  9.         size = 0;  
  10.     }  
  11.       
  12.     // 在头结点前插入  
  13.     public boolean addBeforeHead(E data){  
  14.         Node<E> newNode = new Node<E>(data);  
  15.         if(isEmpty()){  
  16.             head = newNode;  
  17.         }else{  
  18.             head.setPrev(newNode);  
  19.             newNode.setNext(head);  
  20.             head = newNode;  
  21.         }  
  22.         size++;  
  23.         return true;  
  24.     }  
  25.       
  26.     // 在链表尾部插入  
  27.     public boolean addAfterTail(E data){  
  28.         Node<E> newNode = new Node<E>(data);  
  29.         if(isEmpty()){  
  30.             head = newNode;  
  31.         }else{  
  32.             Node<E> tail = get(size);  
  33.             tail.setNext(newNode);  
  34.             newNode.setPrev(tail); // 设置新结点的上一结点  
  35.         }  
  36.         size++;  
  37.         return true;  
  38.     }  
  39.   
  40.     // 插入指定位置的结点  
  41.     public boolean insert(int position, E data) {  
  42.         if(position >= 1 && (position <= size + 1)){  
  43.             Node<E> newNode = new Node<E>(data);  
  44.             if(isEmpty() || position == 1){ // 链表为空或在头结点前插入  
  45.                 addBeforeHead(data);  
  46.             }else if(position == size + 1){ // 在尾结点后插入  
  47.                 Node<E> preNode = get(position - 1);  
  48.                 newNode.setPrev(preNode);  
  49.                 preNode.setNext(newNode);  
  50.             }else// 在其他位置插入  
  51.                 Node<E> preNode = get(position - 1); // 获取position的前一结点  
  52.                 Node<E> afterNode = preNode.getNext(); // 获取未插入结点时position位置对应结点   
  53.                 newNode.setPrev(preNode); // ①  
  54.                 newNode.setNext(afterNode); // ②  
  55.                 afterNode.setPrev(newNode); // ③  
  56.                 preNode.setNext(newNode); // ④  
  57.             }  
  58.             size++;  
  59.             return true;  
  60.         }  
  61.         return false;  
  62.     }  
  63.   
  64.     // 删除指定位置的结点  
  65.     public E delete(int position) {   
  66.         E result = null;  
  67.         if(position >= 1 && position <= size){  
  68.             if(position == 1){ // 删除头结点  
  69.                 result = head.getData();  
  70.                 Node<E> afterHead = head.getNext();  
  71.                 afterHead.setPrev(null);  
  72.                 head.setNext(null);  
  73.                 head = afterHead;   
  74.             }else if(position == size){ // 删除尾结点  
  75.                 Node<E> preNode = get(position - 1); // 获取待删除结点的前一结点  
  76.                 Node<E> delNode = preNode.getNext(); // 获取待删除结点  
  77.                 result = delNode.getData();  
  78.                 preNode.setNext(null);  
  79.             }else// 删除其他结点  
  80.                 Node<E> preNode = get(position - 1); // 获取待删除结点的前一结点  
  81.                 Node<E> delNode = preNode.getNext(); // 获取待删除结点  
  82.                 result = delNode.getData();  
  83.                 Node<E> nextNode = delNode.getNext();// 获取待删除结点的下一结点  
  84.                 preNode.setNext(nextNode); // ①  
  85.                 nextNode.setPrev(preNode); // ②  
  86.             }  
  87.             size--;  
  88.         }  
  89.         return result;  
  90.     }  
  91.       
  92.     // 获取某个位置的结点(正序遍历)  
  93.     public Node<E> get(int position){  
  94.         Node<E> targetNode = null;  
  95.         if(!isEmpty() && position >= 1 && position <= size){   
  96.             targetNode = head;  
  97.             for(int i = 1; i < position ; i++){  
  98.                 targetNode = targetNode.getNext(); // 循环获取对应位置的结点  
  99.             }  
  100.         }  
  101.         return targetNode;  
  102.     }  
  103.       
  104.     // 获取链表的长度  
  105.     public int getSize(){  
  106.         return size;  
  107.     }  
  108.       
  109.     // 判断链表是否为空  
  110.     public boolean isEmpty(){  
  111.         return size == 0;  
  112.     }  
  113.       
  114.     // 打印链表数据  
  115.     public void display(){  
  116.         Node<E> node = head;  
  117.         System.out.print("双向链表: ");  
  118.         for(int i = 0; i < size; i++){  
  119.             System.out.print(" " + node.getData());  
  120.             node = node.getNext();  
  121.         }  
  122.         System.out.println("");  
  123.     }  
  124. }  
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //结点类,包含结点的数据和指向下一个节点的引用  
  2. public class Node<E> {  
  3.     private E data; // 数据域  
  4.     private Node<E> next; // 指针域保存着下一节点的引用  
  5.     private Node<E> prev; // 指针域保存着上一节点的引用 (相比单链表,双向链表多了这个指针)  
  6.       
  7.     public Node() {  
  8.     }  
  9.   
  10.     public Node(E data) {  
  11.         this.data = data;  
  12.     }  
  13.   
  14.     public Node(E data, Node<E> next, Node<E> prev) {  
  15.         this.data = data;  
  16.         this.next = next;  
  17.         this.prev = prev;  
  18.     }  
  19.   
  20.     public E getData() {  
  21.         return data;  
  22.     }  
  23.   
  24.     public void setData(E data) {  
  25.         this.data = data;  
  26.     }  
  27.   
  28.     public Node<E> getNext() {  
  29.         return next;  
  30.     }  
  31.   
  32.     public void setNext(Node<E> next) {  
  33.         this.next = next;  
  34.     }  
  35.   
  36.     public Node<E> getPrev() {  
  37.         return prev;  
  38.     }  
  39.   
  40.     public void setPrev(Node<E> prev) {  
  41.         this.prev = prev;  
  42.     }  
  43. }  
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public class Main {  
  2.     public static void main(String[] args) {  
  3.         DoubleLinkedList<Integer> dll = new DoubleLinkedList<Integer>();  
  4.         dll.addBeforeHead(2);  
  5.         dll.addAfterTail(3);  
  6.         dll.addBeforeHead(1);  
  7.         dll.display();  
  8.         dll.insert(4,4);  
  9.         dll.insert(5,5);  
  10.         dll.insert(6,6);  
  11.         dll.display();  
  12.         dll.delete(6);  
  13.         dll.delete(3);  
  14.         dll.delete(1);  
  15.         dll.display();  
  16.         System.out.println("双向链表的长度为:  " + dll.getSize());  
  17.     }  
  18. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值