【数据结构与算法(Java)】单链表(按顺序添加)

1. 应用场景

  • 当不知道数据量大小的时候,可以使用“链表”来动态储存和处理数据

2. 思路

  • 分类:(本文使用 “有头节点”)
    • 有头节点 链表
    • 无头节点 链表
  • 存储方式:节点
  • 节点结构
    • 数据域(Data):存储 当前节点数据
    • 地址域(Next):指向 下一个节点地址
    • 头指针:数据域无意义,只有指向下一节点的地址域
    • 不一定 是连续存储
    • 数值按照顺序(本文章按照从小到大顺序)
      在这里插入图片描述

3. 数据结构(类结构):

【节点 Node】

(1)成员变量(Field)

  • data: int,节点所储存的数据
  • nextNode: Node,所指向的下一个节点
    private int data;
    private Node nextNode;

(2)初始化 / 构造器(Constructor)

  • 参数传入节点所要储存的数据
  • 初始化节点数据
    public Node(int data) {
        this.data = data;
    }

(3)方法(Methods)

- 两个成员变量的getter和setter
    public int getData() {
        return data;
    }

    public void setData(int data) {
        this.data = data;
    }

    public Node getNextNode() {
        return nextNode;
    }

    public void setNextNode(Node nextNode) {
        this.nextNode = nextNode;
    }
- toString方法
    @Override
    public String toString() {
        return "Node{" +
                "data=" + data +
                '}';
    }

【有序单链表 OrderedSingleLinkedList】

(1)成员变量(Field)

  • headPointer: Node,头节点,不储存数据,只通过自身的nextNode负责储存第一个Node的地址。当有序单链表创建时直接实例化,数据域为0。
    private Node headPointer = new Node(0);

(2)初始化 / 构造器(Constructor)

  • 默认构造器

(3)方法(Methods)

- 添加新节点

addNode(Node) -> void

  • 将头指针赋值到一个临时变量,此临时变量用来储存循环遍历时的当前节点
  • 通过循环遍历寻找 要插入的位置
    • 循环过程中,如果 当前节点的下一节点null,说明到达链表末尾,结束循环,准备将新节点插入当前节点的下一节点位置。
    • 循环过程中,如果当前节点的 下一节点的值大于新节点的值,说明找到需要插入的位置。结束循环,准备将新节点插入当前节点的下一节点位置。
    • 循环过程中,如果上述两条均不符合,则将当前节点的 下一节点赋值给当前节点变量,继续循环。
  • 循环结束后,将新节点插入到 当前节点和当前节点的下一节点之间
    public void addNode(Node newNodePractice) {
        // 1. 头指针赋值到临时变量
        Node currentNode = this.headPointer;

        // 2. 进行循环遍历,寻找新节点应当插入的位置,并插入新节点
        while (true) {
            // (1) 若next节点为null 或 new节点值小于next节点值,说明找到插入点,结束循环
            if (currentNode.getNextNode() == null || newNodePractice.getData() < currentNode.getNextNode().getData()) {
                break;
            }

            // (2) 若new节点值等于next节点值,抛出异常;否则new节点值大于next节点值,将next节点赋值给temp节点
            if (newNodePractice.getData() == currentNode.getNextNode().getData()) {
                throw new RuntimeException("There is a data equals to the new data");
            }
            currentNode = currentNode.getNextNode();
        }

        // 3. 将new节点插入到current节点和next节点之间
        Node tempNode = currentNode.getNextNode();
        currentNode.setNextNode(newNodePractice);
        newNodePractice.setNextNode(tempNode);
    }
- 查找某节点是否存在

isNodeExist(Node) -> boolean

  • 先判断链表是否为空
  • 设置一个 boolean变量 ,用来标识 是否找到了该节点,默认值为false
  • 将头指针赋值到一个临时变量,此临时变量用来储存循环遍历时的当前节点
  • 通过循环遍历寻找 是否存在一个节点与输入节点有相同值的节点
    • 当前节点的下一节点null,说明到达链表末尾,退出循环
    • 若输入节点值等于下一节点值,找到相同节点,设置found为true,退出循环
  • 若上述条件 均不满足,将下一节点赋值给当前节点变量,继续循环
  • 结束循环后,返回 boolean变量
    public boolean isNodeExist(Node inputNodePractice) {
        // 1. 判断链表是否为空,是则抛出异常
        if (this.headPointer.getNextNode() == null) {
            throw new RuntimeException("The single linked list is empty!");
        }

        // 2. 设置boolean来判断是否找到存在的相同值,初始值为false
        boolean found = false;

        // 3. 头指针赋值到临时变量
        Node currentNode = this.headPointer;

        // 4. 进行循环遍历,寻找输入节点的相同节点
        while (true) {
            // (1) 若next节点为null,说明到达链表末尾,退出循环
            if (currentNode.getNextNode() == null) {
                break;
            }
            // (2) 若输入节点值等于next节点值,找到相同节点,设置found为true,退出循环
            if (inputNodePractice.getData() == currentNode.getNextNode().getData()) {
                found = true;
            }
            // (3) 若上述条件均不满足,将next节点赋值给current节点,继续循环
            currentNode = currentNode.getNextNode();
        }

        // 5.返回isExist
        return found;
    }
- 删除某节点

deleteNode(Node) -> void

  • 判断链表是否为空,是则抛出异常
  • 设置boolean变量用来标识是否找到节点,默认值为false
  • 设置临时节点变量,赋值为头节点
  • 进行循环遍历,寻找 待删除节点的相同节点
    • 当前节点的下一节点null,说明到达链表末尾,退出循环
    • 若待删除节点值 等于 下一节点值,找到相同节点,设置found为true,退出循环
    • 若上述条件 均不满足,将下一节点赋值给当前节点,继续循环
  • 判断 是否找到待删除节点
    • 若找到,设置下一节点为 “下一节点的下一节点”,即删除所找到的节点
    • 若未找到,抛出异常
    public void deleteNode(Node nodePractice) {
        // 1. 判断链表是否为空,是则抛出异常
        if (this.headPointer.getNextNode() == null) {
            throw new RuntimeException("The single linked list is empty!");
        }

        // 2. 设置boolean用来标识是否找到节点
        boolean found = false;

        // 3. 设置临时变量,赋值为头节点
        Node currentNode = this.headPointer;

        // 4. 进行循环遍历,寻找待删除节点的相同节点
        while (true) {
            // (1) 若next节点为null,说明到达链表末尾,退出循环
            if (currentNode.getNextNode() == null) {
                break;
            }
            // (2) 若待删除节点值等于next节点值,找到相同节点,设置found为true,退出循环
            if (nodePractice.getData() == currentNode.getNextNode().getData()) {
                found = true;
                break;
            }
            // (3) 若上述条件均不满足,将next节点赋值给current节点,继续循环
            currentNode = currentNode.getNextNode();
        }

        // 5. 判断是否找到待删除节点
        if (found) {
            // (1) 若找到,设置next节点为"next节点的next节点",即删除所找到的节点
            currentNode.setNextNode(currentNode.getNextNode().getNextNode());
        } else {
            // (2) 若未找到,抛出异常
            throw new RuntimeException("The node is not found!");
        }
    }
- 获取全部节点的计数

countNodes() -> int

  • 设置int值用来计数
  • 设置临时节点变量,赋值为头节点
  • 进行循环遍历,每找到一个 非null的节点 count加1
    • 当前节点的下一节点null,退出循环
    • 否则 count 加 1,并将下一节点赋值给当前节点,继续循环
  • 结束循环后,返回count值
    public int countNodes() {
        // 1. 设置int值用来计数
        int count = 0;

        // 2. 设置临时变量,赋值为头节点
        Node currentNode = this.headPointer;

        // 3. 进行循环遍历,每找到一个非null的节点count加1
        while (true) {
            if (currentNode.getNextNode() == null) {
                break;
            }
            count++;
            currentNode = currentNode.getNextNode();
        }

        // 4. 返回count
        return count;
    }
- 打印全部节点的数据

displayAllNodes() -> void

  • 判断链表 是否为空,打印"链表为空"
  • 设置临时节点变量,赋值为头节点
  • 从头节点开始遍历,并打印
    • 当前节点null,退出循环
    • 否则 打印 当前节点的数据,并将下一节点赋值给当前节点,继续循环
    public void displayAllNodes() {
        // 1. 判断链表是否为空,打印"链表为空"
        if (this.headPointer.getNextNode() == null) {
            System.out.println("The single linked list is empty!");
        }

        // 2. 头指针的next赋值到临时变量
        Node tempNode = this.headPointer.getNextNode();

        // 3. 从头节点开始遍历,并打印, 若当前临时节点为null,退出循环
        int count = 0;
        while (tempNode != null) {
            // (1) 若当前节点不为null,打印当前节点的数据
            System.out.println(tempNode.toString());
            count++;

            // (2)将next节点赋值给当前临时节点并,继续循环
            tempNode = tempNode.getNextNode();
        }
        System.out.println("[node count] --> " + count);
    }

4. 完整实现

public class OrderedSingleLinkedList {
    private Node headPointer = new Node(0);

    public void addNode(Node newNodePractice) {
        // 1. 头指针赋值到临时变量
        Node currentNode = this.headPointer;

        // 2. 进行循环遍历,寻找新节点应当插入的位置,并插入新节点
        while (true) {
            // (1) 若next节点为null 或 new节点值小于next节点值,说明找到插入点,结束循环
            if (currentNode.getNextNode() == null || newNodePractice.getData() < currentNode.getNextNode().getData()) {
                break;
            }

            // (2) 若new节点值等于next节点值,抛出异常;否则new节点值大于next节点值,将next节点赋值给temp节点
            if (newNodePractice.getData() == currentNode.getNextNode().getData()) {
                throw new RuntimeException("There is a data equals to the new data");
            }
            currentNode = currentNode.getNextNode();
        }

        // 3. 将new节点插入到current节点和next节点之间
        Node tempNode = currentNode.getNextNode();
        currentNode.setNextNode(newNodePractice);
        newNodePractice.setNextNode(tempNode);
    }

    public boolean isNodeExist(Node inputNodePractice) {
        // 1. 判断链表是否为空,是则抛出异常
        if (this.headPointer.getNextNode() == null) {
            throw new RuntimeException("The single linked list is empty!");
        }

        // 2. 设置boolean来判断是否找到存在的相同值,初始值为false
        boolean found = false;

        // 3. 头指针赋值到临时变量
        Node currentNode = this.headPointer;

        // 4. 进行循环遍历,寻找输入节点的相同节点
        while (true) {
            // (1) 若next节点为null,说明到达链表末尾,退出循环
            if (currentNode.getNextNode() == null) {
                break;
            }
            // (2) 若输入节点值等于next节点值,找到相同节点,设置found为true,退出循环
            if (inputNodePractice.getData() == currentNode.getNextNode().getData()) {
                found = true;
            }
            // (3) 若上述条件均不满足,将next节点赋值给current节点,继续循环
            currentNode = currentNode.getNextNode();
        }

        // 5.返回isExist
        return found;
    }

    public void deleteNode(Node nodePractice) {
        // 1. 判断链表是否为空,是则抛出异常
        if (this.headPointer.getNextNode() == null) {
            throw new RuntimeException("The single linked list is empty!");
        }

        // 2. 设置boolean用来标识是否找到节点
        boolean found = false;

        // 3. 设置临时变量,赋值为头节点
        Node currentNode = this.headPointer;

        // 4. 进行循环遍历,寻找待删除节点的相同节点
        while (true) {
            // (1) 若next节点为null,说明到达链表末尾,退出循环
            if (currentNode.getNextNode() == null) {
                break;
            }
            // (2) 若待删除节点值等于next节点值,找到相同节点,设置found为true,退出循环
            if (nodePractice.getData() == currentNode.getNextNode().getData()) {
                found = true;
                break;
            }
            // (3) 若上述条件均不满足,将next节点赋值给current节点,继续循环
            currentNode = currentNode.getNextNode();
        }

        // 5. 判断是否找到待删除节点
        if (found) {
            // (1) 若找到,设置next节点为"next节点的next节点",即删除所找到的节点
            currentNode.setNextNode(currentNode.getNextNode().getNextNode());
        } else {
            // (2) 若未找到,抛出异常
            throw new RuntimeException("The node is not found!");
        }
    }

    public int countNodes() {
        // 1. 设置int值用来计数
        int count = 0;

        // 2. 设置临时变量,赋值为头节点
        Node currentNode = this.headPointer;

        // 3. 进行循环遍历,每找到一个非null的节点count加1
        while (currentNode.getNextNode() != null) {
            count++;
            currentNode = currentNode.getNextNode();
        }

        // 4. 返回count
        return count;
    }

    public void displayAllNodes() {
        // 1. 判断链表是否为空,打印"链表为空"
        if (this.headPointer.getNextNode() == null) {
            System.out.println("The single linked list is empty!");
        }

        // 2. 头指针的next赋值到临时变量
        Node tempNode = this.headPointer.getNextNode();

        // 3. 从头节点开始遍历,并打印, 若当前临时节点为null,退出循环
        int count = 0;
        while (tempNode != null) {
            // (1) 若当前节点不为null,打印当前节点的数据
            System.out.println(tempNode.toString());
            count++;

            // (2)将next节点赋值给当前临时节点并,继续循环
            tempNode = tempNode.getNextNode();
        }
        System.out.println("[node count] --> " + count);
    }
}

class Node {
    private int data;
    private Node nextNode;

    public Node(int data) {
        this.data = data;
    }

    @Override
    public String toString() {
        return "Node{" +
                "data=" + data +
                '}';
    }

    public int getData() {
        return data;
    }

    public void setData(int data) {
        this.data = data;
    }

    public Node getNextNode() {
        return nextNode;
    }

    public void setNextNode(Node nextNode) {
        this.nextNode = nextNode;
    }

}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值