zoukankan      html  css  js  c++  java
  • 数据结构02-链表

    说明:由于该数据结构是由java并且是原生实现,所以与C有一些出入,不过原理是相同的

    1.链表的定义

        为了表示线性表元素a与a+1的逻辑关系,存储数据时,除了存储元素本身的信息之外,还存储了直接后继元素的位置信息。这两部分组成的数据元素被称为“结点”,一个结点分为两部分,存放数据元素信息的部分被称为数据域,

        存放直接后继元素位置的部分被称为指针域。

        单链表:结点指针域只存放直接后继元素位置的链表,也叫单向链表。

        双链表:结点指针域同时存放前驱元素和后继元素位置的链表,也叫双向链表。

        循环链表:一般的链表尾结点(最后一个结点)的指针域一般null,但是有的链表将最后一个节点的指针域指向头结点,构成一个环,称作循环链表。

        头结点: 一个链表的头节点,就是指针域指向该链表的第一个结点的结点,一般用来唯一确定一个链表(也有的链表是不带头结点的,那时我们通过链表的第一个结点来确定链表),注意:头结点的数据与是null

    2.实现原理

        链表的每一个结点包括两部分,数据域和指针域,数据域用来存储数据,指针域用来存储后继结点的位置。

     1 class Link<T>{
     2     /**
     3     *用来存储数据
     4     */
     5     T data;
     6     /**
     7     *用来存储下一结点位置
     8      */
     9     Link next;
    10 }

    3.链表的基本操作

        1.初始化 init() 创建一个链表

        2.清空 clear() 清空一个链表

        3.销毁 destroy() 销毁链表

        4.在头部插入一个结点 insertFront()

        5.在尾部插入一个结点 insertBackend()

        6.在任意位置插入一个结点 insertIndex()

        7.删除任意位置元素 delete()

        8.查找元素 find()

        9.获取指定位置节点的值 get()

    4.代码实现

      4.1链表代码实现

      1 package com.xiaobai.linelist;
      2 
      3 /**
      4  * @Author: xiaobai
      5  * @Date: 2019/5/1 9:00
      6  * @email:
      7  * @address:
      8  * @desc 模拟单链表操作
      9  * @Version 1.0
     10  */
     11 @SuppressWarnings("ALL")
     12 public final class Link<T> {
     13     /**
     14      * data 是要存储的数据
     15      */
     16     private T data;
     17     /**
     18      * next是下一结点的引用位置
     19      */
     20     public Link<T> next;
     21 
     22     /**
     23      * 初始化操作 构造方法返回一个空结点
     24      */
     25     public Link(){
     26         this.next = null;
     27         this.data = null;
     28     }
     29 
     30     /**
     31      * 构造一个新的链表结点
     32      * 新结点是没有后继结点的 所以直接null
     33      * @param data 数据
     34      */
     35     public Link(T data){
     36         this.data = data;
     37         this.next = null;
     38     }
     39 
     40     /**
     41      * 清空链表操作
     42      * @param link 要被清空的链表头节点
     43      */
     44     public void clear(){
     45         //让每一个结点的引用都为 null GC 自动回收
     46         Link<T> link = this;
     47         while(link.next!=null){
     48             Link curr = link.next;
     49             link.next = link.next.next;
     50             curr = null;
     51         }
     52         link = null;
     53     }
     54 
     55     /**
     56      * 销毁链表 这里的销毁和清空我认为没有什么区别,所以直接调用
     57      * 如果大家认为有区别的话,可以与我交流
     58      * @param link 被销毁的链表
     59      */
     60     public void destroy(){
     61         this.clear();
     62     }
     63 
     64     /**
     65      * 在链表的头部插入一个结点(默认是带头结点的链表)
     66      * @param head 链表的头节点
     67      * @param data 被插入的数据
     68      * @return 插入结果
     69      */
     70     public boolean insertFront(T data){
     71         //先构建一个新的结点
     72         Link<T> node = new Link<T>(data);
     73         try {
     74             //将结点插入到头部 即 新节点后继指向原来的第一个结点  头节点后继指向新节点
     75             node.next = this.next;
     76             this.next = node;
     77             return true;
     78         }catch (Exception e){
     79             e.printStackTrace();
     80             return false;
     81         }
     82     }
     83 
     84     /**
     85      * 在链表的尾部插入一个结点
     86      * @param head 链表头节点
     87      * @param data 要插入的数据
     88      * @return 插入结果
     89      */
     90     public boolean insertBackend(T data){
     91         //先构建一个新的结点
     92         try {
     93             Link<T> node = new Link<T>(data);
     94             //然后找到链表的尾
     95             Link<T> point = this.next;
     96             while(point.next!=null){
     97                 point = point.next;
     98             }
     99             //插入
    100             point.next = node;
    101             return true;
    102         } catch (Exception e) {
    103             e.printStackTrace();
    104             return false;
    105         }
    106     }
    107 
    108     /**
    109      * 在任意位置插入一个结点
    110      * @param head 要插入的链表
    111      * @param i  插入位置 从0开始
    112      * @param data 插入的数据
    113      * @return 插入结果
    114      */
    115     public boolean insertIndex(int i,T data){
    116         Link curr = this.next;
    117         //空链表 拒绝插入
    118         if(null == curr && i > 0){
    119             return false;
    120         }
    121         int count = 0;
    122         //找到被插入的位置(要找被插入位置前一个)
    123         while(count != i-1 && null != curr){
    124             curr = curr.next;
    125             count ++;
    126         }
    127         //如果循环提前结束 说明i值过大
    128         if(count != i-1){
    129             return false;
    130         }
    131         //开始插入节点
    132         Link<T> node = new Link<T>(data);
    133         node.next = curr.next;
    134         curr.next = node;
    135         return true;
    136     }
    137 
    138     /**
    139      * 删除任意位置元素
    140      * @param i 被删除的位置  从0 开始
    141      * @return 被删除的元素 删除失败返回null
    142      */
    143     public T delete(int i){
    144         T del = null;
    145         int count = 0;
    146         Link<T> curr = this.next;
    147         //找到被删除结点的前一个结点
    148         while (curr != null&& count < i-1){
    149             curr = curr.next;
    150             count++;
    151         }
    152         //如果不满足条件 删除失败
    153         if(count!=i-1){
    154             return del;
    155         }
    156         //如果找到 执行删除操作 (GC 自动释放)
    157         del = curr.next.data;
    158         curr.next = curr.next.next;
    159         return del;
    160     }
    161 
    162     /**
    163      * 查找元素是否存在  可能需要重写存储对象的equals方法
    164      * @param data 被查找元素
    165      * @return 查找结果
    166      */
    167     public boolean find(T data){
    168         Link curr = this.next;
    169         while(curr != null){
    170             if(curr.data.equals(data)||curr.data ==data){
    171                 return true;
    172             }
    173             curr = curr.next;
    174         }
    175         return false;
    176     }
    177 
    178     /**
    179      * 获取指定位置的元素
    180      * @param i 位置
    181      * @return 获取到的值 没有返回null
    182      */
    183     public T get(int i) {
    184         T data = null;
    185         Link<T> curr = this.next;
    186         int count = 0;
    187         while(count!=i && curr!=null){
    188             curr = curr.next;
    189             count ++;
    190         }
    191         if(count == i && curr!= null){
    192             data = curr.data;
    193         }
    194         return data;
    195     }
    196 
    197     @Override
    198     public String toString() {
    199         StringBuilder sb = new StringBuilder().append("HashCode = "+this.hashCode()).append(" {head -> ");
    200         Link<T> curr = this.next;
    201         while (curr!=null){
    202             sb.append(curr.data+" -> ");
    203             curr = curr.next;
    204         }
    205         sb.append(" null}");
    206         return sb.toString();
    207     }
    208 }

      4.2  测试代码及结果

     1 /**
     2  * @Author: xiaobai
     3  * @Date: 2019/5/1 9:42
     4  * @email: 
     5  * @address:
     6  * @Version 1.0
     7  */
     8 public class TestLink {
     9     public static void main(String[] args) {
    10         System.out.println("初始化链表");
    11         Link<Integer> link = new Link<>();
    12         System.out.println("当前链表: "+link);
    13 
    14         System.out.println("在前端插入一个元素 5");
    15         link.insertFront(5);
    16         System.out.println("当前链表: "+link);
    17 
    18         for(int i=1;i<=10;i++){
    19             link.insertBackend(i);
    20         }
    21         System.out.println("依次从后端继续插入10个数后: "+link);
    22 
    23         link.insertIndex(3,100);
    24         //索引从0开始
    25         System.out.println("在第三个位置上插入100以后的链表 "+link);
    26 
    27         System.out.println("在第100个位置上插入0 "+link.insertIndex(100,0));
    28 
    29         System.out.println("删除第三个位置上的元素"+link.delete(3));
    30         System.out.println(link);
    31 
    32         System.out.println("查找元素10的结果"+link.find(10));
    33         System.out.println("查找元素100的结果"+link.find(100));
    34 
    35         System.out.println("获取第3个结点的值 "+link.get(3));
    36         System.out.println("获取第999个结点的值 "+link.get(999));
    37 
    38         link.clear();
    39         System.out.println("执行清空操作后的链表: "+link);
    40 
    41         link.destroy();
    42 
    43     }
    44 }

          运行结果图:

  • 相关阅读:
    【转载】不出国如何练就一口流利的英语?
    【转载】什么能力很重要——4
    【转载】什么能力很重要,但大多数人却没有?——3
    【转载】什么能力很重要,但大多数人却没有?——2
    【转载】什么能力很重要,但大多数人却没有?——1
    【转载】有哪些东西是你读研究生以后才懂的?
    JDBCTemplate基本使用
    Druid数据库连接池基本使用
    C3P0连接池
    简单理解数据库连接池(JDBC)
  • 原文地址:https://www.cnblogs.com/xiaobai1202/p/10799114.html
Copyright © 2011-2022 走看看