• Java实现单链表


    一、分析

      单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。链表中的数据是以结点来表示的,每个结点由元素和指针构成。在Java中,我们可以将单链表定义成一个类,单链表的基本操作即是类的方法,而结点就是一个个实例化的对象,每个对象中都有“元素值”和“下一结点地址”两个属性。在“下一结点地址”属性中存储的是下一个对象的引用,这样,一个个对象连在一起就成为了单链表。

      单链表有以下基本操作:

        1、初始化单链表

        2、销毁单链表

        3、清空单链表

        4、检测单链表是否为空

        5、返回单链表的元素个数

        6、返回单链表中指定位置元素的值

        7、返回单链表中第一个与指定值相同的元素的位置

        8、返回指定元素的直接前驱

        9、返回指定元素的直接后继

        10、向指定位置插入元素

        11、删除指定位置的元素

        12、遍历单链表

      为了方便对单链表进行操作,我们还需要引入一个头结点,头结点中不存储元素值,只存储单链表第一个结点的地址。初始化单链表即创建头结点,而销毁单链表即销毁头结点。

    二、实现

    1、定义类属性和构造函数

     1 class InitList{
     2     
     3     private int [] data = new int[1];   //用来存储元素值,之所以用数组而不用整型,是为了用null来表示头结点
     4     
     5     private InitList nextList;       //下一结点地址
     6     
     7     public InitList() {           //创建头结点的构造函数
     8         this.data = null;
     9         this.nextList = null;
    10     }
    11     
    12     public InitList(int data) {      //创建普通结点的构造函数
    13         this.data[0] = data;
    14         this.nextList = null;
    15     }
    16 }

    2、清空单链表

    1 public void clearList() {
    2     this.nextList = null;          //将头结点的下一结点地址(即单链表的第一个结点的地址)置空,则单链表会因缺少引用而被jvm回收,实现清空
    3 }

    3、检测单链表是否为空

    1 public boolean listEmpty() {
    2     if(this.nextList == null) {      //通过判断头结点的下一结点地址是否为空,即可判断单链表是否为空
    3         return true;
    4     }
    5     return false;
    6 }

    4、返回单链表的元素个数

     1 public int listLength() {
     2 
     3     InitList theList = this.nextList;        //获取头结点的下一结点地址
     4     int i = 0;                         //计数器初始化
     5 
     6     for (i = 0; theList != null; i++) {      //循环判断结点地址是否为空,如果不为空,则表明存在结点,计数器i加一;如果为空,则表明已到达单链表尾部,退出循环
     7         theList = theList.nextList;         //取下一结点进行判断
     8     }
     9     return i;                      //返回计数器的值
    10 }

    5、返回单链表中指定位置元素的值

     1 public int [] getElem(int site) {
     2 
     3     if(site < 1) {                      //判断输入的位置是否合法
     4         return null;
     5     }
     6 
     7     InitList theList = this;              //得到头结点的地址
     8 
     9     for (int i = 0; i < site; i++) {        //循环读取结点,直到指定的位置
    10         theList = theList.nextList;        //获取下一结点的地址
    11         if(theList == null) {            //如果下一结点地址为空,则表明已经到达单链表末尾,指定的位置超出了单链表的长度
    12             return null;              //未取到元素,返回null
    13         }
    14     }
    15     return theList.data;              //返回指定位置元素值
    16 }

    6、返回单链表中第一个与指定值相同的元素的位置

     1 public int locateElem(int value) {
     2 
     3     InitList theList = this.nextList;
     4 
     5     for(int i = 1; theList != null; i++) {     //如果取得的结点不为空,执行循环
     6         if(theList.data[0] == value) {        //比较结点值与给定的值是否相等
     7             return i;                  //相等返回结点位置
     8         }
     9         theList = theList.nextList;         //取下一结点地址
    10     }
    11 
    12     return 0;                      //未找到则返回零
    13 }

    7、返回指定元素的直接前驱

     1 public int [] priorElem(int value) {
     2 
     3     InitList theList = this.nextList;
     4 
     5     if(theList == null) {                    //如果头结点的下一结点为空,则表明单链表为空,返回null
     6         return null;
     7     }
     8 
     9     InitList theNextList = this.nextList.nextList;     //获取单链表的第二个结点
    10     int [] ret = new int[this.listLength()];         //创建一个与单链表长度相同的数组,用来存储找到的直接前驱的值
    11     int i = 1;                           //计数器
    12 
    13     while (theNextList != null) {               //因为单链表的第一个结点没有直接前驱,因此从第二个结点开始循环
    14         if(theNextList.data[0] == value) {         //如果与给定值相等,则取得其前驱,计数器加一
    15             ret[i] = theList.data[0];
    16             i++;
    17         }
    18         theList = theNextList;                //取下一地址,准备下一循环
    19         theNextList = theNextList.nextList;
    20     }
    21 
    22     if(i == 1) {                        //i为1表明未取到直接前驱
    23         return null;
    24     }
    25 
    26     ret[0] = i - 1;                      //将计数器的值存入数组第0位
    27     return ret;
    28 }

    8、返回指定元素的直接后继

     1 public int [] nextElem(int value) {              //与获取直接前驱类似,这里不再赘述
     2 
     3     InitList theList = this.nextList;
     4 
     5     if(theList == null) {
     6         return null;
     7     }
     8 
     9     InitList theNextList = this.nextList.nextList;
    10     int [] ret = new int[this.listLength()];
    11     int i = 1;
    12 
    13     while (theNextList != null) {
    14         if(theList.data[0] == value) {
    15             ret[i] = theNextList.data[0];
    16             i++;
    17         }
    18         theList = theNextList;
    19         theNextList = theNextList.nextList;
    20     }
    21 
    22     if(i == 1) {
    23         return null;
    24     }
    25 
    26     ret[0] = i - 1;
    27     return ret;
    28 }

    9、向指定位置插入元素

     1 public boolean listInsert(int site,int value) {
     2 
     3     if(site < 1) {                        //判断指定位置是否合法
     4         return false;
     5     }
     6
    7
       InitList list = new InitList(value); 8 InitList theNextList = this; 9 InitList theList = null; 10 11 for(int i = 0; i < site; i++) {             //循环读取到指定位置 12 theList = theNextList; 13 if(theList == null) {                //如果为空,表示已到单链表末尾,返回false 14 return false; 15 } 16 theNextList = theNextList.nextList; 17 } 18 19 list.nextList = theNextList;                //将新结点插入指定位置中 20 theList.nextList = list; 21 return true; 22 }

    10、删除指定位置的元素

     1 public boolean listDelete(int site) {
     2 
     3     InitList theList = this;
     4     InitList theNextList = this.nextList;
     5 
     6     if(site < 1 || theNextList == null) {        //判断指定位置是否合法和单链表是否为空
     7         return false;
     8     }else if(site == 1) {                  //如果要删除的是第一个结点,则直接删除
     9         theList.nextList = theNextList.nextList;
    10         return true;
    11     }
    12 
    13     for(int i = 1; i < site; i++) {            //循环读取到指定位置
    14         theNextList = theNextList.nextList;
    15         if(theNextList == null) {
    16             return false;
    17         }
    18         theList = theList.nextList;
    19     }
    20 
    21     theList.nextList = theNextList.nextList;       //删除指定位置的结点
    22     return true;
    23 }

    11、遍历单链表

     1 public String traverseList() {          //这里通过输出单链表来表示遍历
     2 
     3     InitList theList = this.nextList;
     4     String s = "";                 //用来存储单链表的值
     5 
     6     while(theList != null) {           //循环获取结点值
     7         s += theList.data[0] + "、";
     8         theList = theList.nextList;
     9     }
    10 
    11     if(s.length() == 0) {             //如未获取到值,直接返回s
    12         return s;
    13     }
    14 
    15     return s.substring(0,s.length() - 1);   //去除最后的顿号后返回
    16 }

    三、小结

      以上就是单链表用Java的实现,由于只定义了整数的数组,因此只能操作整数数据,但单链表的基本思想都已实现。

    四、纠正

      隔了一段时间又回来看代码,猛地发现这段代码其实还不够完善。(⊙x⊙;)

      将单链表的基本操作定义成了InitList类的方法,实例化结点时,会使每个结点都拥有这些方法,然而其实只有头结点需要这些方法,其他结点都不需要。

      因此可以将InitList类定义成头节点类,而其他节点定义成头节点的内部类,这样,就只有头节点可以操作其他节点。

      由于要修改的地方太多,这里我就不修改了,放在这里提醒自己。(就是因为懒……(><))

  • 相关阅读:
    ViewPager+导航条实现方式比较---------来自互联网
    ScrollView重写实现监听
    android:layout_gravity和android:gravity
    解决Android Studio添加依赖时出现“Manifest merger failed
    Android SD卡读取简单操作
    Android文件读取简单操作
    20160623
    Mac 下两款 Markdown 编辑器 Mou/MacDown 大 PK
    iOS开发编码建议与编程经验(书写规范)
    iOS开发调试技巧总结
  • 原文地址:https://www.cnblogs.com/ysyasd/p/10739930.html
Copyright © 2020-2023  润新知