04 Java基本数据结构之链表

系列文章目录

01 Java基本数据结构之栈实现
02 Java基本数据结构之队列实现
03 Java基本数据结构之优先级队列
04 Java基本数据结构之链表


如有错误,还请指出


前言

链表这一部分内容较多,同时实现起来最开始的时候也是笔者最开始不太理解的,掌握基础链表后,再进一步实现双端链表、有序链表、双向链表以及用链表实现栈、队列。


一、栈(简述)

在链表中,每个数据项都被包含在“链节点”(Node)中,一个链节点是某个类的对象,这个类可以叫做节点类Node。每个Node对象都包含一个对下一个节点引用的字段(通常叫做next)。此外,链表本身对象中有一个字段指向对第一个链节点的引用。

![在这里插入图片描述](https://img-blog.csdnimg.cn/a3d6325d311047e7a81756197e59424f.png

二、链表实现

后面文章会介绍抽象数据类型ADT,明白这个概念更容易理解数据结构。

2.1 节点类

Node各个字段的存取权限设为public,如果他们是private,必须提供公开的方法来访问它们,需要额外的代码。另外,这里假设存储了两种数据,一个 int 类型的数据,一个double类型的数据,实际英语中,可能包含更多的数据项,通常用一个包含这些数据的类的对象来代替这些数据项。

public class Node {
    public int iData; //设为公开,私有则必须提供公开的方法才访问,需要额外代码
    public double dData;
    public Node next;
    //-----------------------------------

    public Node(int iData, double dData) {
        this.iData = iData;
        this.dData = dData;
        this.next = null; //可以不用初始化,引用类型对象创建时默认null
    }

 

    //-----------------------------------
    public void display() {
        System.out.println("Node{" + "iData=" + iData + ", dData=" + dData + '}');
    }
}

2.2 单链表类

package list;
/*
* 01单链表
* isEmpty
* insertFirst 链表首部插入,新节点称为first节点,指向原来的first节点
* deletFirst first节点的next节点为新节点
* displayList 从first节点开始,打印数据,移动直到 节点的next为null
*             未插入节点时,即first=null,只插入一个节点时,这个节点和first只是一个节点
* 查找和删除指定链节点(包含特定数据)
* find 不是目标节点,找下一个
* delete 找到后再删除节点,将断开前后连接起来,考虑头节点的特殊情况:
* */
public class LinkList {
    private Node first; //first 相当于一个指针

    public LinkList() {
        this.first = null; //可以不用初始化
    }
    public boolean isEmpty(){
        return first==null;
    }
    //-----------------------------------
    public void insertFirst(int iD,double dD){
        Node newNode=new Node(iD,dD);
        newNode.next=first;
        first=newNode;
    }
    public Node deletFirst() throws Exception {
        if (isEmpty()) throw new Exception("链表无节点");
        Node temp=first;
        first=first.next;
        return temp; // 返回删除的头节点
    }
    public void displayList(){
        Node current=first; //临时头节点
        while (current!=null){
            current.display();
            current=current.next;
        }
    }
    // 上述为链表的基本功能,下面增加了两个方法,查找和删除指定节点
    //----------------查找和删除指定链节点(包含特定数据)-------------------
    // 这里假设查找 iData为目标值的节点
    public Node find(int key){
        Node tempFirst=first;
        while (tempFirst.iData!=key){
            tempFirst=tempFirst.next;  //重新赋了一个节点的地址
            if (tempFirst==null) return null;
        }
        return tempFirst;
    }

    public Node delete(int key) throws Exception {
        if (isEmpty()) throw new Exception("链表为空");
        Node current=first; //当前节点
        Node previous = null; // 当前节点的上个节点

        while (current.iData!=key){
            previous=current;
            current=current.next;
            if (current==null) return null;
        }//找到目标节点

        if (current==first)  //为 头节点
            first=first.next; //first=first.next=null 删除成功
        else
            previous.next=current.next; //连接断裂
        return current;
    }

    public Node getFirst() {
        return first;
    }
}

三、注意点

3.1 first 头节点

LinkList链表类只包含一个数据项:即对链表中第一个链节点的引用,叫做first。它是唯一的链表需要维护的永久消息,用以定位所有其他的链节点。从 first 出发,沿着链表通过每个链节点的next字段,就可以找到其他的节点。
构造函数把 first 赋值为 null,实际上这不是必须的,因为引用类型在创建指出就会自动赋值为null值。然后构造函数明确说明了赋初值,强调了 first 是怎么开始运作的。当 first值为null时,表明链表中没有数据项。如果有,first字段中应该存有对第一个节点的引用值。isEmpty()方法就用这种方法来判断链表是否为空。
另外,在笔者看来,first 这个可以理解为实际的节点,也可以理解为一个指针概念,永远指向头节点。

3.2 insertFirst()

在表头插入一个新的节点,这非常容易,只需要使新创建的节点的next字段等于原来的 first值,然后改变first值,让它指向新创建的链接点。

    public void insertFirst(int iD,double dD){
        Node newNode=new Node(iD,dD);
        newNode.next=first;
        first=newNode;
    }

3.3 deletFirst()

deletFirst()方法是 insertFirst() 方法的逆操作。通过把 first 重新指向第二个节点,断开了和第一个节点的连接。

    public Node deletFirst() throws Exception {
        if (isEmpty()) throw new Exception("链表无节点");
        Node temp=first;
        first=first.next;
        return temp;
    }

3.4 displayList() 遍历打印链表

为了显示链表,从first开始,沿着链表从一个节点到另一个节点。变量 current 按顺序指向每一个节点。current首先指向 first ,然后使用语句 current=current.next; 不断移向下个节点,同时尾节点的next 字段是 null 值,作为结束条件。

    public void displayList(){
        Node current=first; //临时头节点
        while (current!=null){
            current.display();
            current=current.next;
        }
    }

3.5 find( key )、delete( key )

find() 方法 很像上述的链表打印方法,通过不断移动节点,在每个节点处检查节点数据项里的关键值是否为目标值,找到了则返回对该节点的引用,反之移动到下个节点直到遍历完。

delete() 方法和 find() 类似,先搜索要删除的节点。然而它需要掌握的不仅是指向当前节点(current) 的引用,还有指向当前节点的前一个(previous)节点的引用。因为要删除当前节点,需要把前一个节点和后一个节点连在一起。同时需要注意如果目标节点是头节点,则处理不一样。

   // 这里假设查找 iData为目标值的节点
    public Node find(int key){
        Node tempFirst=first;
        while (tempFirst.iData!=key){
            tempFirst=tempFirst.next;  //重新赋了一个节点的地址
            if (tempFirst==null) return null;
        }
        return tempFirst;
    }

    public Node delete(int key) throws Exception {
        if (isEmpty()) throw new Exception("链表为空");
        Node current=first; //当前节点
        Node previous = null; // 当前节点的上个节点

        while (current.iData!=key){
            previous=current;
            current=current.next;
            if (current==null) return null;
        }//找到目标节点

        if (current==first)  //为 头节点
            first=first.next; //first=first.next=null 删除成功
        else
            previous.next=current.next; //连接断裂
        return current;
    }

测试

    @Test
    public void LinkList() throws Exception {
        /************测试单链表***********/
        LinkList list1=new LinkList();
        list1.insertFirst(1,10);
        list1.insertFirst(2,20);
        list1.insertFirst(3,30);
        list1.insertFirst(4,40);
        list1.displayList();
        System.out.println("删除的节点为:");
        list1.deletFirst().display();
        list1.deletFirst().display();
        System.out.println("当前链表");
        list1.displayList();
        //
        System.out.println("测试指定删除和查找");
        list1.find(2).display();
        list1.delete(2);
        list1.displayList();
}

/*
Node{iData=4, dData=40.0}
Node{iData=3, dData=30.0}
Node{iData=2, dData=20.0}
Node{iData=1, dData=10.0}
删除的节点为:
Node{iData=4, dData=40.0}
Node{iData=3, dData=30.0}
当前链表
Node{iData=2, dData=20.0}
Node{iData=1, dData=10.0}
测试指定删除和查找
Node{iData=2, dData=20.0}
Node{iData=1, dData=10.0}
 */
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值