Java语言描述--单链表的设计与实现--数据结构

数据结构--单链表的设计与实现

首先了解其定义:
单链表:如果每个结点只设置一个指向其后结点的指针成员,这样的链表称为线性单向链接表,简称单链表。
何为指针成员呢,在链表中每个结点不仅包含有元素本身的信息(称为数据成员),而且包含有元素之间的逻辑关系的信息。
指针成员:一个结点包含有后续结点的地址信息或者前驱结点的地址信息,称为指针成员。
与C语言当中的指针类似,C语言当中的指针存放的是地址值;但Java中并不存在指针的概念,这里的指针成员存放的是后继结点或者是前驱结点的引用,引用存放的仍为其相对应的地址值。概念不同,功能相同。

了解了单链表的概念之后来看相应的图解:
单链表只有一个头结点,且在初始化头结点时,是不存放数据的,只有一个指向为null的next结点:

在这里插入图片描述
对于每个结点head、s、s1……等我没有直接使用方框代替,我的理解是,每一个new出的结点对象,默认包含其对应构造方法内的全部内容,当你想往构造方法找添加内容时,对应的对象所分配的内存空间也更多。这里使用椭圆内嵌方框也是以我自己的理解进行构图。对于我对构造函数的理解,详见上一期,文章内含有我对构造函数的理解及顺序表的实现。

接着再进行了解,单链表个成员之间是如何建立连接的,具体的建立连接的方式有两种:
头插法建表:相应图解为:

在这里插入图片描述
图片文字有点小,可以放大看。过程就全在图中喽

相应代码:

//用头插法建立单链表
    public void GreatLoneList(Object[] a){
        LoneListOne<Object> s;
        for (int i = 0; i < a.length; i++) {
            s = new LoneListOne<>(a[i]);
            s.next = head.next;
            head.next = s;
        }
    }

尾插法建表:相应图解为:
在这里插入图片描述
相应代码:

//用尾插法建表
    public void GreatLoneListEnd(Object[] a){
        LoneListOne<Object> s,t;
        t = head;
        for (int i = 0; i < a.length; i++) {
            s = new LoneListOne<>(a[i]);
            t.next = s;
            t = s;
        }
        t.next = null;
    }

用尾插法更符合我们平常的操作,其代码也更简洁

了解了单链表的实现原理及建表方法后,我们就可以着力将整个单链表的所有基本模块实现喽:
本次实现单链表需要创建3个类,各类具体功能在后讲解 一.编写一个类建立结点结构:

class LoneListOne<Object>{
    Object data;
    LoneListOne<Object> next;
    //建立单链表头结点模型
    public LoneListOne(){
        next = null;
    }
    //建立单链表数据结点模型
    public LoneListOne(Object d){
        data = d;
        next = null;
    }
}

头结点初始时是不存放数据的,只有一个空指针成员null。

  1. 二.编写另一个类,初始化头结点及实现单链表的基本功能(增删改查):
  • 1.创立一个头结点:
  •  //建立头结点
        LoneListOne<Object> head = new LoneListOne<>();
    
  • 2.头插法的代码实现:
  • //用头插法建立单链表
        public void GreatLoneList(Object[] a){
            LoneListOne<Object> s;
            for (int i = 0; i < a.length; i++) {
                s = new LoneListOne<>(a[i]);
                s.next = head.next;
                head.next = s;
            }
        }
    
    3.尾插法的代码实现:
    //用尾插法建表
        public void GreatLoneListEnd(Object[] a){
            LoneListOne<Object> s,t;
            t = head;
            for (int i = 0; i < a.length; i++) {
                s = new LoneListOne<>(a[i]);
                t.next = s;
                t = s;
            }
            t.next = null;
        }
    
  • 4.求单链表的长度:
  • //求线性表的长度
        public int size(){
            LoneListOne<Object> p = head;
            int count = 0;
            while(p.next!=null){
                count++;
                p = p.next;
            }
            return count;
        }
    
  • 5.代码实现向单链表中增加元素:
  • //增:向单链表中末尾增加一个元素
        public void Add(Object e){
            LoneListOne<Object> p = head;
            LoneListOne<Object> s = new LoneListOne<>(e);
            while(p.next!=null){
                p = p.next;
                p.next = s;
            }
        }
    
  • 6.代码实现在单链表中删除元素: 删除元素时,首先需找到其结点所在位置,再改变其指向
    1).找结点
  • //找到序号为i的结点,为删做准备
        public LoneListOne<Object> geti(int i){
            LoneListOne<Object> p = head;
            int j = -1;
            while(j<i){
                j++;
                p = p.next;
            }
            return p;
        }
    

    2).删元素

    //删:在单链表中删除第i个元素
        public void Delete(int i,Object e){
            if (i<0 ||i>size()-1) {
                throw new IllegalArgumentException("元素i不在有效范围之内!");
            }
            LoneListOne<Object> p = geti(i-1);
            p.next = p.next.next;
        }
    
  • 7.代码实现单链表中元素修改: 找结点,改元素
  • //改:设置线性表中序号为i的元素为e
        public void SetElem(int i,Object e){
            if(i<0||i>size()-1){
                throw new IllegalArgumentException("元素i不在有效范围之内!");
            }
            LoneListOne<Object> p = geti(i);
            p.data = e;
        }
    
  • 8.代码实现单链表中元素的查找:
  •  //查:寻找序号为i的结点,返回线性表中序号为i的元素
        public Object getElem(int i){
            LoneListOne<Object> p = head;
            int j = -1;
            while(j<i){
                j++;
                p = p.next;
            }
            return p.data;
        }
    
  • 9.代码实现返回单链表中所有元素: 原理为将各个结点遍历,将各结点中的data数据赋给字符串
  • //将单链表中全部元素转换为字符串并返回
        public String ToString(){
            String ans = "";
            LoneListOne<Object> p = head.next;
            while(p!=null){
                ans+=p.data+" ";
                p=p.next;
            }
            return ans;
        }
    
    以上代码均在 class LoneListTwo{} 泛型类中实现
    在主类中创建LoneListTwo对象调用方法实现其基本功能:
    public class LoneList {
        public static void main(String[] args) {
            Integer[] a={1,2,3,4,5};
            LoneListTwo<Object> loneListTwo = new LoneListTwo<>();
            loneListTwo.GreatLoneList(a);
            String s = loneListTwo.ToString();
            System.out.println("输出单链表:"+s);
            loneListTwo.GreatLoneListEnd(a);
            String s1 = loneListTwo.ToString();
            System.out.println("输出单链表:"+s1);
        }
    
    }
    
    完整代码如下:
    package com.other;
    
    class LoneListOne<Object>{
        Object data;
        LoneListOne<Object> next;
        //建立单链表头结点模型
        public LoneListOne(){
            next = null;
        }
        //建立单链表数据结点模型
        public LoneListOne(Object d){
            data = d;
            next = null;
        }
    }
    class LoneListTwo<Object>{
        //建立头结点
        LoneListOne<Object> head = new LoneListOne<>();
        //用头插法建立单链表
        public void GreatLoneList(Object[] a){
            LoneListOne<Object> s;
            for (int i = 0; i < a.length; i++) {
                s = new LoneListOne<>(a[i]);
                s.next = head.next;
                head.next = s;
            }
        }
        //用尾插法建表
        public void GreatLoneListEnd(Object[] a){
            LoneListOne<Object> s,t;
            t = head;
            for (int i = 0; i < a.length; i++) {
                s = new LoneListOne<>(a[i]);
                t.next = s;
                t = s;
            }
            t.next = null;
        }
        //求线性表的长度
        public int size(){
            LoneListOne<Object> p = head;
            int count = 0;
            while(p.next!=null){
                count++;
                p = p.next;
            }
            return count;
        }
        //增:向单链表中末尾增加一个元素
        public void Add(Object e){
            LoneListOne<Object> p = head;
            LoneListOne<Object> s = new LoneListOne<>(e);
            while(p.next!=null){
                p = p.next;
                p.next = s;
            }
        }
        //找到序号为i的结点,为删做准备
        public LoneListOne<Object> geti(int i){
            LoneListOne<Object> p = head;
            int j = -1;
            while(j<i){
                j++;
                p = p.next;
            }
            return p;
        }
        //删:在单链表中删除第i个元素
        public void Delete(int i,Object e){
            if (i<0 ||i>size()-1) {
                throw new IllegalArgumentException("元素i不在有效范围之内!");
            }
            LoneListOne<Object> p = geti(i-1);
            p.next = p.next.next;
        }
        //改:设置线性表中序号为i的元素为e
        public void SetElem(int i,Object e){
            if(i<0||i>size()-1){
                throw new IllegalArgumentException("元素i不在有效范围之内!");
            }
            LoneListOne<Object> p = geti(i);
            p.data = e;
        }
        //查:寻找序号为i的结点,返回线性表中序号为i的元素
        public Object getElem(int i){
            LoneListOne<Object> p = head;
            int j = -1;
            while(j<i){
                j++;
                p = p.next;
            }
            return p.data;
        }
        //将单链表中全部元素转换为字符串并返回
        public String ToString(){
            String ans = "";
            LoneListOne<Object> p = head.next;
            while(p!=null){
                ans+=p.data+" ";
                p=p.next;
            }
            return ans;
        }
    
    }
    public class LoneList {
        public static void main(String[] args) {
            Integer[] a={1,2,3,4,5};
            LoneListTwo<Object> loneListTwo = new LoneListTwo<>();
            loneListTwo.GreatLoneList(a);
            String s = loneListTwo.ToString();
            System.out.println("输出单链表:"+s);
            loneListTwo.GreatLoneListEnd(a);
            String s1 = loneListTwo.ToString();
            System.out.println("输出单链表:"+s1);
        }
    
    }
    

    结果如下:
    在这里插入图片描述

    这里主要写的是单链表的实现原理,主类中我没有将各方法全部调用,读者可自行复制代码进行尝试。当理解了原理之后,可尝试独立完成创建。

    我这里创建的都是泛型类,使用了Object,其实不必这样定义LoneListOne类和LoneListTwo类,同时也可将Object修饰变量替换成相应的包装类。创建包装类好处就是可以指代任意类型,当你不确定使用什么数据类型时。

    前面也说了,创建对象并初始化时,会默认拥有对应构造方法内的全部内容。所以第一个类为创建各结点的"形状",即第一个类创建的对象都是链表中的每个结点,为什么要再创一个LoneListTwo类实现其方法,初始化后的对象可调用本类中的所有成员及成员方法。即第二个类创建的每一个对象都是一个链表。如果在LoneListOne类创建这些结点对象,那么新创立的结点,如s可调用结点head,这肯定是不合理的,这样创建出来的就不是一个链表了,是一个"怪物"。那么为什么要在主类LoneList创建LoneListTwo类对象利用其调用各方法呢,这当然是Java面向对象的特性了。实现结构与表现分离,也可将LoneListTwo类中定义的所有东西放在主类LoneList中。在一个类中实现这些功能。

    若觉得内容稍可,请留下你们的

    在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值