zoukankan      html  css  js  c++  java
  • 单链表的代码实现

    写在前面:

      链表采用一组地址任意的存储单元存放线性表中的数据元素,链式结构的线性表不会按线性的逻辑顺序来保存数据元素,它需要在每一个元素里保存一个引用下一个数据元素的引用(或者叫指针)。它的每个节点都必须包含数据元素本身和一或两个用来引用上一个/下一个节点的引用。

    优点:由于不必须按顺序存储,链表在插入、删除数据元素时比顺序线性表快得多。使用链表结构可以克服顺序线性表(基于数组)需要预先知道数据大小的缺点,链表可以充分利用计算机内存空间,实现灵活的内存动态管理。

    缺点:链表在查找一个节点或者访问特点编号的节点则比顺序线性表慢得多。由于链表结构失去了数组随机存取的优点,同时链表由于增加了节点的指针域,空间开销比较大。

    以下使用Java语言实现一个单链表:

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

    测试类:

     1 package com.ietree.basic.datastructure.linklist;
     2 
     3 public class LinkListTest {
     4     public static void main(String[] args) {
     5 
     6         LinkList<String> list = new LinkList<String>();
     7         list.insert("aaaa", 0);
     8         list.add("bbbb");
     9         list.add("cccc");
    10         list.insert("dddd", 1);
    11         System.out.println(list);
    12         list.delete(2);
    13         System.out.println(list);
    14         System.out.println("cccc在链表中的位置:" + list.locate("cccc"));
    15         System.out.println("链表中索引2处的元素:" + list.get(2));
    16     }
    17 }

    程序输出:

    [aaaa, dddd, bbbb, cccc]
    [aaaa, dddd, cccc]
    cccc在链表中的位置:2
    链表中索引2处的元素:cccc
  • 相关阅读:
    t-SNE可视化(MNIST例子)
    numpy得到数组的index
    Latex的各种帽子
    Mac OSX安装 GitLab 5.x
    yii2 关系...
    基于git的源代码管理模型——git flow
    spl_autoload_register
    如何創建一個自己的 Composer/Packagist 包 (PHP)
    正则表达式语法
    sublime php插件
  • 原文地址:https://www.cnblogs.com/Dylansuns/p/6783682.html
Copyright © 2011-2022 走看看