zoukankan      html  css  js  c++  java
  • 【数据结构】- 双向链表的实现

    题目:

     1 双向升序链表结构定义如下:
     2 class Node {
     3 
     4         private int value;// 保存节点的数据
     5         
     6         private Node pre, next;// 保存上个节点的引用、指向下一个节点的引用
     7 }
     8 编程实现对该双向链表的插入、删除操作
     9 public Node insert(Node head, int value);//返回头节点
    10 public void delete(Node head, int value);

    双向链表实现

      1 package com.ruihai.collection.test;
      2 
      3 /**
      4  * 双向升序链表
      5  * 
      6  * 参考Java.util包的LinkedList实现
      7  * @author shenruihai.com
      8  */
      9 public class LinkedList {
     10 
     11     // 定义一个内部类Node,Node实例代表链表的节点
     12     private class Node {
     13 
     14         private int value;// 保存节点的数据
     15         
     16         private Node pre;// 保存上个节点的引用
     17        
     18         private Node next; // 指向下一个节点的引用
     19 
     20         // 无参构造器
     21         public Node() {
     22         }
     23 
     24         // 初始化全部属性的构造器
     25         public Node(int value, Node pre, Node next) {
     26 
     27             this.value = value;
     28             this.pre = pre;
     29             this.next = next;
     30 
     31         }
     32     }
     33 
     34     // 保存该链表的头节点
     35     private Node header;
     36     // 保存该链表的尾节点
     37     private Node tail;
     38     // 保存该链表中已包含的节点数
     39     private int size;
     40 
     41     // 创建空链表
     42     public LinkedList() {
     43 
     44         // 空链表,header和tail都是null
     45         header = null;
     46         tail = null;
     47 
     48     }
     49 
     50     // 以指定数据元素来创建链表,该链表只有一个元素
     51     public LinkedList(int element) {
     52 
     53         header = new Node(element, null, null);
     54         // 只有一个节点,header、tail都指向该节点
     55         tail = header;
     56         size++;
     57 
     58     }
     59 
     60     // 返回链表的长度
     61     public int length() {
     62         return size;
     63     }
     64 
     65     // 获取链式线性表中索引为index处的元素
     66     public int get(int index) {
     67 
     68         return getNodeByIndex(index).value;
     69 
     70     }
     71 
     72     // 根据索引index获取指定位置的节点
     73     public Node getNodeByIndex(int index) {
     74 
     75         if (index < 0 || index > size - 1) {
     76             throw new IndexOutOfBoundsException("线性表索引越界");
     77         }
     78         
     79         if (index <= size / 2) {
     80 
     81             // 从header节点开始
     82             Node current = header;
     83             for (int i = 0; i <= size / 2 && current != null; i++, current = current.next) {
     84                 if (i == index) {
     85 
     86                     return current;
     87 
     88                 }
     89             }
     90 
     91         } else {
     92 
     93             // 从tail节点开始搜索
     94             Node current = tail;
     95             for (int i = size - 1; i > size / 2 && current != null; i++, current = current.pre) {
     96                 if (i == index) {
     97 
     98                     return current;
     99 
    100                 }
    101             }
    102         }
    103         return null;
    104     }
    105 
    106     // 查找链式线性表中指定元素的索引
    107     public int locate(int element) {
    108 
    109         // 从头结点开始搜索
    110         Node current = header;
    111         for (int i = 0; i < size && current != null; i++, current = current.next) {
    112 
    113             if (String.valueOf(current.value).equals(element)) {
    114                 return i;
    115             }
    116 
    117         }
    118         return -1;
    119 
    120     }
    121 
    122     // 向线性链表的指定位置插入一个元素
    123     public void insert(int element, int index) {
    124 
    125         if (index < 0 || index > size) {
    126             throw new IndexOutOfBoundsException("线性表索引越界");
    127         }
    128 
    129         // 如果还是空链表
    130         if (header == null) {
    131 
    132             add(element);
    133 
    134         } else {
    135 
    136             // 当index为0时,也就是在链表头处插入
    137             if (index == 0) {
    138 
    139                 addAtHeader(element);
    140 
    141             } else {
    142 
    143                 // 获取插入点的前一个节点
    144                 Node pre = getNodeByIndex(index - 1);
    145                 // 获取插入点的节点
    146                 Node next = pre.next;
    147                 // 让新节点的next引用指向next节点,pre引用指向pre节点
    148                 Node newNode = new Node(element, pre, next);
    149                 // 让pre的next节点指向新节点
    150                 pre.next = newNode;
    151                 // 让pre的下一个节点的pre指向新节点
    152                 next.pre = newNode;
    153                 size++;
    154             }
    155         }
    156     }
    157 
    158     // 采用尾插法为链表添加新节点
    159     public void add(int element) {
    160 
    161         // 如果该链表还是空链表
    162         if (header == null) {
    163 
    164             header = new Node(element, null, null);
    165             // 只有一个节点,header、tail都指向该节点
    166             tail = header;
    167 
    168         } else {
    169 
    170             // 创建新节点,新节点的pre指向原tail节点
    171             Node newNode = new Node(element, tail, null);
    172             // 让尾节点的next指向新增的节点
    173             tail.next = newNode;
    174             // 以新节点作为新的尾节点
    175             tail = newNode;
    176         }
    177         size++;
    178     }
    179 
    180     // 采用头插法为链表添加新节点
    181     public void addAtHeader(int element) {
    182         // 创建新节点,让新节点的next指向原来的header
    183         // 并以新节点作为新的header
    184         header = new Node(element, null, header);
    185         // 如果插入之前是空链表
    186         if (tail == null) {
    187 
    188             tail = header;
    189 
    190         }
    191         size++;
    192     }
    193 
    194     // 删除链式线性表中指定索引处的元素
    195     public int delete(int index) {
    196 
    197         if (index < 0 || index > size - 1) {
    198 
    199             throw new IndexOutOfBoundsException("线性表索引越界");
    200 
    201         }
    202         Node del = null;
    203         // 如果被删除的是header节点
    204         if (index == 0) {
    205 
    206             del = header;
    207             header = header.next;
    208             // 释放新的header节点的pre引用
    209             header.pre = null;
    210 
    211         } else {
    212 
    213             // 获取删除节点的前一个节点
    214             Node pre = getNodeByIndex(index - 1);
    215             // 获取将要被删除的节点
    216             del = pre.next;
    217             // 让被删除节点的next指向被删除节点的下一个节点
    218             pre.next = del.next;
    219             // 让被删除节点的下一个节点的pre指向pre节点
    220             if (del.next != null) {
    221 
    222                 del.next.pre = pre;
    223 
    224             }
    225 
    226             // 将被删除节点的pre、next引用赋为null
    227             del.pre = null;
    228             del.next = null;
    229 
    230         }
    231         size--;
    232         return del.value;
    233     }
    234 
    235     // 删除链式线性表中最后一个元素
    236     public int remove() {
    237 
    238         return delete(size - 1);
    239 
    240     }
    241 
    242     // 判断链式线性表是否为空表
    243     public boolean empty() {
    244 
    245         return size == 0;
    246 
    247     }
    248 
    249     // 清空线性表
    250     public void clear() {
    251 
    252         // 将底层数组所有元素赋为null
    253         header = null;
    254         tail = null;
    255         size = 0;
    256 
    257     }
    258 
    259     public String toString() {
    260 
    261         // 链表为空链表
    262         if (empty()) {
    263 
    264             return "[]";
    265 
    266         } else {
    267 
    268             StringBuilder sb = new StringBuilder("[");
    269             for (Node current = header; current != null; current = current.next) {
    270                
    271                 sb.append(String.valueOf(current.value).toString() + ", ");
    272 
    273             }
    274             int length = sb.length();
    275             return sb.delete(length - 2, length).append("]").toString();
    276 
    277         }
    278 
    279     }
    280 
    281     // 倒序toString
    282     public String reverseToString() {
    283 
    284         if (empty()) {
    285 
    286             return "[]";
    287 
    288         } else {
    289 
    290             StringBuilder sb = new StringBuilder("[");
    291             for (Node current = tail; current != null; current = current.pre) {
    292 
    293                 sb.append(String.valueOf(current.value).toString() + ", ");
    294 
    295             }
    296             int length = sb.length();
    297             return sb.delete(length - 2, length).append("]").toString();
    298 
    299         }
    300 
    301     }
    302     
    303 }

    小记:这是今天下午朋友发给我的一道面试题,看到的时候想:“这不就是考的双向链表嘛,链表这部分我还是很清楚的”,但是通过代码去实现的时候才发现双向链表通过代码实现还是比较麻烦的,最后参考LinkedList的源码,写了这段代码。

  • 相关阅读:
    centos7 安装 tesseract4.1
    08 图的数据结构和算法
    07 树形结构及其算法
    05 数组与链表算法
    06 堆栈与队列算法
    04 查找与哈希算法
    03 排序算法
    javascript 标签轮播
    tomcat URI get 参数中文传到后台 乱码 URIEncoding
    javascript 标签切换
  • 原文地址:https://www.cnblogs.com/juihai/p/10544639.html
Copyright © 2011-2022 走看看