单向、双向链表

链表

一、介绍

1、介绍

​ 链表是一种非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列节点(链表中每一个元素称为节点)组成,节点可以在运行时动态生成。每个节点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个节点地址的指针域

(1)单向链表(单链表)是链表的一种,它由节点组成,每个节点都包含下一个节点的指针

(2)双向链表(双链表)是链表的一种。和单链表一样,双链表也是由节点组成,它的每个数据节点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个节点开始,都可以很方便地访问它的前驱节点和后继节点

2、图解

(1)单向链表

在这里插入图片描述

(2)双向链表

在这里插入图片描述

二、单向链表

1、存于节点的User实体
package com.dashu.linear_structure.linked_list;

public class User {

    /**
     * 姓名
     */
    private String name;

    /**
     * 年龄
     */
    private int age;


    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

2、单向节点
public class Node {

    /**
     * 编号
     */
    private int no;

    /**
     * 用户
     */
    private User user;

    /**
     * 下一个节点
     */
    private Node next;


    public Node(int no, User user) {
        this.no = no;
        this.user = user;
    }


    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public Node getNext() {
        return next;
    }

    public void setNext(Node next) {
        this.next = next;
    }
}

3、带头节点的单向链表
package com.dashu.linear_structure.linked_list;

import java.util.Stack;

/**
 * @Author: dashu
 * @Description: 包含头节点的链表
 * @Date: 2021/12/6 23:55
 * @Version: 1.0
 */
public class HeadLinkedList {

    /**
     * 初始化头节点
     */
    private Node headNode = new Node(0, new User("", 0));


    /**
     * 末尾添加节点
     *
     * @param node
     */
    public void add(Node node) {

        /**
         * 获取头节点
         */
        Node temp = headNode;

        /**
         * 循环遍历节点
         */
        while (true) {


            /**
             * 节点后的下一个节点为null,则链表遍历结束,退出循环
             */
            if (temp.getNext() == null) {
                break;
            }

            /**
             * 节点向后移一位
             */
            temp = temp.getNext();

        }

        /**
         * 添加节点
         */
        temp.setNext(node);

    }


    /**
     * 有序添加节点
     *
     * @param node
     */
    public void addByOrderly(Node node) {

        /**
         * 获取头节点
         */
        Node temp = headNode;


        /**
         * 循环遍历节点
         */
        while (true) {


            /**
             * 节点后的下一个节点为null,则链表遍历结束,退出循环
             */
            if (temp.getNext() == null) {
                break;
            }

            /**
             * 获取遍历节点的下一个节点的编号,判断是否与添加节点的编号相等
             *
             * 若相等的话,则可知,节点已经存在于链表
             *
             * 不可以在添加
             *
             * 抛出异常信息
             *
             */
            if (temp.getNext().getNo() == node.getNo()) {
                throw new RuntimeException("元素已存在,请勿重复添加");
            }


            /**
             * 获取遍历节点的下一个节点的编号,判断是否大于添加节点的编号
             *
             * 若大于的话,则可知,节点不存在于链表
             *
             * 且节点应该添加到当前节点的下一个节点
             *
             * 退出循环
             *
             */
            if (temp.getNext().getNo() > node.getNo()) {
                break;
            }


            /**
             * 节点向后移一位
             */
            temp = temp.getNext();

        }

        /**
         * 添加节点的下一个节点为当前节点的下一个节点
         */
        node.setNext(temp.getNext());

        /**
         * 当前节点的下一个节点为添加的节点
         */
        temp.setNext(node);

    }


    /**
     * 节点修改
     *
     * @param node
     */
    public void update(Node node) {

        /**
         * 判断头节点后的下一个节点是否为空,为空,说明链表没有数据
         */
        if (headNode.getNext() == null) {
            System.out.println("链表为空,修改失败");
            return;
        }

        /**
         * 获取头节点的下一个节点
         */
        Node temp = headNode.getNext();


        /**
         * 用于判断节点是否在链表
         */
        boolean flag = false;

        /**
         * 循环遍历节点
         */
        while (true) {


            /**
             * 节点为null,则链表遍历结束,退出循环
             */
            if (temp == null) {
                break;
            }

            /**
             * 判断遍历的节点编号是否于参数节点的编号相等
             *
             *  相等的话,则可判定该节点存在于链表中,flag = true,退出循环
             *
             *  并且修改的节点是 就是temp
             */
            if (temp.getNo() == node.getNo()) {
                flag = true;
                break;
            }


            /**
             * 节点向后移一位
             */
            temp = temp.getNext();
        }


        /**
         *  节点存在于链表
         */
        if (flag) {

            /**
             * 修改节点
             */
            temp.setUser(node.getUser());
        } else {

            /**
             *  节点不存在于链表
             */
            System.out.println("节点不存在,修改失败");
        }

    }

    /**
     * 根据编号删除节点
     *
     * @param no
     */
    public void delete(int no) {


        /**
         * 判断头节点后的下一个节点是否为空,为空,说明链表没有数据
         */
        if (headNode.getNext() == null) {
            System.out.println("链表为空,删除失败");
            return;
        }

        /**
         * 获取头节点
         */
        Node temp = headNode;

        /**
         * 用于判断节点是否在链表
         */
        boolean flag = false;

        /**
         * 循环遍历节点
         */
        while (true) {


            /**
             * 节点后的下一个节点为null,则链表遍历结束,退出循环
             */
            if (temp.getNext() == null) {
                break;
            }

            /**
             * 判断节点下一个节点的编号,是否与参数no相等
             *
             *  相等的话,则可判定该节点存在于链表中,flag = true,退出循环
             *
             *  并且节点是 temp 后的下一个节点
             */
            if (temp.getNext().getNo() == no) {
                flag = true;
                break;
            }

            /**
             * 节点向后移一位
             */
            temp = temp.getNext();

        }

        /**
         *  节点存在于链表
         */
        if (flag) {

            /**
             * 删除节点
             */
            temp.setNext(temp.getNext().getNext());

        } else {

            /**
             *  节点不存在于链表
             */
            System.out.println("节点不存在,删除失败");
        }

    }


    /**
     * 打印链表
     */
    public void print() {

        /**
         * 判断头节点后的下一个节点是否为空,为空,说明链表没有数据
         */
        if (headNode.getNext() == null) {
            System.out.println("链表为空");
            return;
        }

        /**
         * 获取头节点后的第一个节点
         */
        Node temp = headNode.getNext();

        /**
         * 循环遍历
         */
        while (true) {

            /**
             * 节点为null,链表遍历结束,退出循环
             */
            if (temp == null) {
                break;
            }

            /**
             * 打印
             */
            System.out.println("[编号:" + temp.getNo() + "用户名:" + temp.getUser().getName() + "年龄:" + temp.getUser().getAge() + "]");

            /**
             * 节点向后移一位
             */
            temp = temp.getNext();

        }

    }


    /**
     * 获取链表有效节点数(包含头节点)
     *
     * @return
     */
    public int size(Node headNode) {

        /**
         * 获取头节点
         */
        Node temp = headNode;

        /**
         * 有效节点数
         */
        int i = 0;

        /**
         * 循环遍历节点
         */
        while (true) {

            /**
             * 节点为null,则链表遍历结束,退出循环
             */
            if (temp == null) {
                break;
            }
            /**
             * 有效节点数+1
             */
            i++;

            /**
             * 节点向后移一位
             */
            temp = temp.getNext();

        }


        return i;

    }

    /**
     * 查询单链表倒数第n个节点
     *
     * @param n
     * @return
     */
    public Node getNodeByReverse(int n) {

        /**
         * 判断头节点后的下一个节点是否为空,为空,说明链表没有数据
         */
        if (headNode.getNext() == null) {
            System.out.println("链表为空,查询失败");
            return null;
        }

        /**
         * 获取链表有效节点数
         */
        int size = size(headNode);


        /**
         * 判断输入值是否大于有效节点数,如果大于,则无法取到节点
         */
        if (n < 0 || n > size) {

            System.out.println("输入值大于链表有效为节点数");
            return null;

        }

        /**
         * 有效节点数减去输入值倒序n
         * 得到的n就是正序n
         *
         */
        n = size - n;

        /**
         * 代表节点的位置
         */
        int i = 0;


        /**
         * 获取头节点
         */
        Node temp = headNode;


        /**
         * 循环遍历节点
         */
        while (true) {

            /**
             * i 等于  n,则得到查询的节点
             */
            if (i == n) {
                return temp;
            }

            /**
             * 节点位置 + 1
             */
            i++;


            /**
             * 节点向后移一位
             */
            temp = temp.getNext();

        }


    }


    /**
     * 链表反转
     */
    public void reversalHeadLinkedList() {

        /**
         * 判断头节点后的下一个节点是否为空,为空,说明链表没有数据
         */
        if (headNode.getNext() == null) {
            System.out.println("链表为空");
            return;
        }


        /**
         * 判断有效节点数是否小于3
         *
         * 小于3的话,则有效节点只有头节点和一个节点,无需反转了
         */
        if (headNode.getNext().getNext() == null) {
            System.out.println("有效节点只有2个(头节点+一个节点),无需反转");
            return;
        }


        /**
         * 获取第一个节点
         */
        Node temp = headNode.getNext();

        /**
         * 创建一个临时节点
         */
        Node next = null;

        /**
         * 创建一个临时头节点
         */
        Node tempHeadNode = new Node(0, null);


        /**
         * 循环遍历节点
         */
        while (true) {

            /**
             * 节点为null,则链表遍历结束,退出循环
             */
            if (temp == null){
                break;
            }

            /**
             * 获取下一个节点
             */
            next = temp.getNext();


            temp.setNext(tempHeadNode.getNext());


            tempHeadNode.setNext(temp);

            /**
             * 下一个节点赋值
             */
            temp = next;
        }


        /**
         * 头节点的下一个节点设置为临时头节点的下一个节点,完成链表反转
         */
        headNode.setNext(tempHeadNode.getNext());

    }


    /**
     * 逆序打印
     */
    public void printByReverse(){

        Stack<Node> stack = new Stack<>();

        Node temp = headNode.getNext();

        while (true){

            if (temp == null){
                break;
            }

            stack.add(temp);

            temp = temp.getNext();
        }


       while (stack.size() != 0){
            Node node = stack.pop();
            System.out.println("[编号:" + node.getNo() + "用户名:" + node.getUser().getName() + "年龄:" + node.getUser().getAge() + "]");
        }

    }


    /**
     * 两个链表合并,并有序,取出重复的
     * @param headLinkedList
     * @return
     */
    public HeadLinkedList merge(HeadLinkedList headLinkedList){


        Node temp = headNode;

        Node temp2 = headLinkedList.headNode.getNext();

        Node temp3 = null;

        while (true){

            if (temp2 == null){
                break;
            }

            temp3 = temp2.getNext();

            while (true){

                if (temp.getNext() == null || temp2.getNo() < temp.getNext().getNo()){
                    temp2.setNext(temp.getNext());
                    temp.setNext(temp2);
                    temp = headNode;
                    break;
                }


                if (temp2.getNo() == temp.getNext().getNo()){
                    temp = headNode;
                    break;
                }

                temp = temp.getNext();

            }

            temp2 = temp3;


        }


        return this;




    }

}

三、双向链表

1、双向节点
public class BothwayNode {



    /**
     * 编号
     */
    private int no;

    /**
     * 用户
     */
    private User user;


    /**
     * 上一个
     */
    private BothwayNode last;

    /**
     * 下一个节点
     */
    private BothwayNode next;


    /**
     * 构造方法
     * @param no
     * @param user
     */
    public BothwayNode(int no, User user) {
        this.no = no;
        this.user = user;
    }


    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public BothwayNode getLast() {
        return last;
    }

    public void setLast(BothwayNode last) {
        this.last = last;
    }

    public BothwayNode getNext() {
        return next;
    }

    public void setNext(BothwayNode next) {
        this.next = next;
    }
}

2、带头节点的双向链表
public class BothwayHeadLinkedList {


    private BothwayNode headBothwayNode = new BothwayNode(-1, null);


    /**
     * 链表末尾添加
     * <p>
     * 思路:
     * <p>
     * 循环遍历链表,得到的节点x若next为null
     * <p>
     * 退出循环
     * <p>
     * 为x节点的next赋值加入的节点y
     * <p>
     * 为y节点的last赋值x节点
     *
     * @param bothwayNode
     */
    public void add(BothwayNode bothwayNode) {

        /**
         * 临时节点变量
         */
        BothwayNode temp = headBothwayNode;


        /**
         * 循环
         */
        while (true) {

            /**
             * 遍历到末尾,退出循环
             */
            if (temp.getNext() == null) {
                break;
            }

            /**
             * 节点已存在
             */
            if (temp.getNext().getNo() == bothwayNode.getNo()) {
                throw new RuntimeException("节点已存在");
            }

            /**
             * 节点向后移
             */
            temp = temp.getNext();

        }

        /**
         * 为next为null的temp赋值添加的节点
         */
        temp.setNext(bothwayNode);

        /**
         * 为添加的节点的last赋值temp
         */
        bothwayNode.setLast(temp);

    }


    /**
     * 有序添加
     *
     * @param bothwayNode
     */
    public void addByOrderly(BothwayNode bothwayNode) {

        /**
         * 临时节点变量
         */
        BothwayNode temp = headBothwayNode;

        /**
         * 循环
         */
        while (true) {


            /**
             * 遍历到末尾,退出循环
             */
            if (temp.getNext() == null) {
                break;
            }

            /**
             * 节点已存在
             */
            if (temp.getNext().getNo() == bothwayNode.getNo()) {
                throw new RuntimeException("节点已存在");
            }

            /**
             * 若节点的下一个节点的编号大于加入节点的编号,退出循环。节点应该添加到当前节点的next
             */
            if (temp.getNext().getNo() > bothwayNode.getNo()) {
                break;
            }

            /**
             * 节点向后移
             */
            temp = temp.getNext();

        }


        /**
         * 若temp为链表最后一个节点,则直接将节点添加到末尾
         */
        if (temp.getNext() == null) {

            temp.setNext(bothwayNode);
            bothwayNode.setLast(temp);

        } else {

            /**
             * 修改temp中next的节点向上指向添加的节点
             */
            temp.getNext().setLast(bothwayNode);

            /**
             * 添加的节点下一个指向temp的next节点
             */
            bothwayNode.setNext(temp.getNext());

            /**
             * temp的next指向添加的节点
             */
            temp.setNext(bothwayNode);

            /**
             * 添加的节点指向temp
             */
            bothwayNode.setLast(temp);
        }


    }


    /**
     * 根据编号删除一个节点
     *
     * @param no
     */
    public void delete(int no) {


        /**
         * 临时节点变量
         */
        BothwayNode temp = headBothwayNode.getNext();

        /**
         * 链表为空
         */
        if (temp == null) {
            System.out.println("链表为空");
            return;
        }

        /**
         * 用于判断节点是否存在于链表
         */
        boolean flag = false;

        /**
         * 循环
         */
        while (true) {

            /**
             * 遍历到末尾,退出循环
             */
            if (temp == null) {
                break;
            }

            /**
             * 节点存在,退出循环
             */
            if (temp.getNo() == no) {
                flag = true;
                break;
            }

            /**
             * 节点向后移
             */
            temp = temp.getNext();

        }


        /**
         * 节点存在
         */
        if (flag) {

            /**
             * 节点的上一个节点next指向节点的下一个节点
             */
            temp.getLast().setNext(temp.getNext());

            /**
             * 若该节点不是最后一个节点
             *
             * 则节点的下一个节点last指向节点的上一个节点
             */
            if (temp.getNext() != null) {

                temp.getNext().setLast(temp.getLast());
            }

        } else {
            System.out.println("节点不存在");
        }

    }


    /**
     * 修改节点
     *
     * @param bothwayNode
     */
    public void update(BothwayNode bothwayNode) {

        /**
         * 临时节点变量
         */
        BothwayNode temp = headBothwayNode.getNext();

        /**
         * 链表为空
         */
        if (temp == null) {
            System.out.println("链表为空");
            return;
        }


        /**
         * 用于判断节点是否存在于链表
         */
        boolean flag = false;

        /**
         * 循环
         */
        while (true) {

            /**
             * 遍历到末尾,退出循环
             */
            if (temp == null) {
                break;
            }

            /**
             * 节点存在,退出循环
             */
            if (temp.getNo() == bothwayNode.getNo()) {
                flag = true;
                break;
            }

            /**
             * 节点向后移
             */
            temp = temp.getNext();

        }

        /**
         * 节点存在
         */
        if (flag) {

            /**
             * 修改节点的user属性
             */
            temp.setUser(bothwayNode.getUser());

        } else {
            System.out.println("节点不存在");
        }


    }


    /**
     * 链表打印
     */
    public void print() {

        /**
         * 临时节点变量
         */
        BothwayNode temp = headBothwayNode.getNext();

        /**
         * 链表为空
         */
        if (headBothwayNode.getNext() == null) {
            System.out.println("链表为空...");
            return;
        }


        /**
         * 循环
         */
        while (true) {

            /**
             * 遍历到末尾,退出循环
             */
            if (temp == null) {
                break;
            }

            /**
             * 打印
             */
            System.out.println("[编号:" + temp.getNo() + "用户名:" + temp.getUser().getName() + "年龄:" + temp.getUser().getAge() + "]");


            /**
             * 节点向后移
             */
            temp = temp.getNext();

        }

    }

}

  • 3
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大树下躲雨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值