实验一 线性表的顺序存储与实现_java实现:初识链表

今天来谈谈链表

数组与链表分别属于线性表的两种基本存储结构:顺序存储结构和链式存储结构。

顺序存储结构:用一段地址连续的存储单元依次存储线性表的数据元素。

链式存储结构:地址可以连续也可以不连续的存储单元存储数据元素。

链式存储结构包括单链表,双链表,循环链表。

链表优劣势:使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大,检索时遍历需要从头开始导致效率低。链表最明显的好处就是,常规数组排列关联项目的方式可能不同于这些数据项目在记忆体或磁盘上顺序,数据的存取往往要在不同的排列顺序中转换。链表允许插入和移除表上任意位置上的节点,但是不允许随机存取。

单向链表:

单向链表只有一个指针域,在整个节点中数据域用来存储数据元素,指针域用于指向下一个具有相同结构的节点。

f8c71e9f2d777df12add252d0bb2e1d6.png

34ef879ea717569cd31de1f6b13a789b.png

要实现链表首先定义节点类,有数据域(存储数据,类型自定)+引用域(存储下一个节点,用于节点链接)

public 

接着就可以写链表类来实现链表的功能了

包括头结点root 与中间的n个数据节点node(包括尾部节点last),主要有几个功能要实现:添加新节点到末尾,添加新节点到指定位置,获取链表大小,获取指定位置的节点数据,移除指定位置的节点

public class LinkedList {
    //链表的长度
    private int size = 0;
    //链表的头结点,内容为null
    private Node root = new Node(null);
    //链表的尾部:尾插法
    private Node last = root;

    //构造方法,初始化链表
    public LinkedList() {
    }

    /**
     * add()方法:
     * 尾差法:添加新节点到链表的末尾
     * @param data:添加的数据
     */
    public void add(Object data) {
        //创建本node对象的时候初始化数据:data
        Node node = new Node(data);

        //尾差法:添加到链表的末尾
        //设置尾部last的下一个为:node
        last.setNext(node);
        //更新链表尾部last
        last = node;
        //size增加
        size++;

    }

   

    /**
     * 获取链表大小
     *
     * @return :链表长度
     */
    public int size() {
        return size;
    }

    /**
     * 获取链表第index的数据data
     *
     * @param index :要获取的第i个链表
     * @return :第index的个链表的数据内容
     */
    public Object get(int index) {

        Node node = root.getNext();

        if (index < 0 || index > size) {
            return null;
        }

        for (int i = 0; i < index; i++) {
            node = node.getNext();
        }

        return node.getData();
    }

    /**
     * 移除第index的节点node
     *
     * @param index :第i个
     * @return
     */
    public Object remove(int index) {
        Node node = root.getNext();
        if (index < 0 || index > size) {
            return 0;
        }
        //若要移除的index为第一个node,index为0,不存在index-1,则单独设置
        if (index == 0) {
            //setNext链接上一个和下一个 :上一个为root,下一个为node.getNext()
            root.setNext(node.getNext());
            //清除该节点的引用域为null:next
            node.setNext(null);
            size--;
        }
        //移除的index不为0
        else {
            //获取三个节点:上一个node、这个removenode、下一个nextnode
            //获取要移除node的上一个node
            for (int i = 0; i < index - 1; i++) {
                node = node.getNext();
            }
            // 获取要移除的node
            Node removenode = node.getNext();
            // 获取要移除的下一个node
            Node nextnode = removenode.getNext();

            // setNext链接上一个和下一个:上一个为node,下一个为nextnode
            node.setNext(nextnode);
            //清除该node的引用域为null:next
            removenode.setNext(null);
            size--;
        }
        return 0;
    }
}

如果对单链表的操作能够掌握的话,剩下的这几种链表,相信也能很快掌握,只不过把node中的基本数据改一下,增删的时候多一两行代码。

对于循环链表,你可以想象成y一个闭环的链表。也就是最后一个元素又指向了第一个元素。双向链表每一个节点既指向前驱又指向后继。

077c5014fe08e00077727b13075665da.png

双向链表相对于单链表还是比较复杂的,毕竟每个节点多了一个前驱,因此对于插入和删除要格外小心。双向链表的优点在于对每个节点的相邻接点操作时候,效率会比较高。

be0390256522bcd3726b5bd5061fc4ba.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值