java实现单向链表

逻辑溯风使
• 阅读 1408

单向链表

  • 以节点的方式来存储,包含data和next
  • 在内存中,链表的各个节点不一定是连续存储的
  • 链表分有头节点的链表和没有头节点的链表,头节点用head表示
  • 代码主要是单向链表的增删改查
import java.util.Stack;

public class Demo2 {
    public static void main(String[] args) {
        MyLinkedList linkedList = new MyLinkedList();
        //创建用户节点,并插入链表
        UserNode user1 = new UserNode(1, "一一");
        UserNode user3 = new UserNode(3, "三三");
        UserNode user2 = new UserNode(2, "二二");
        linkedList.addNode(user1);
        linkedList.addNode(user3);
        linkedList.addNode(user2);
        linkedList.getList();
        System.out.println();

        //按id大小插入
        System.out.println("有序插入");
        UserNode user5 = new UserNode(5, "五五");
        UserNode user4 = new UserNode(4, "四四");
        linkedList.addByOrder(user5);
        linkedList.addByOrder(user4);
        linkedList.getList();
        System.out.println();

        //按id修改用户信息
        System.out.println("修改用户信息");
        UserNode userEdit = new UserNode(1, "新一一");
        linkedList.changeNode(userEdit);
        linkedList.getList();
        System.out.println();

        //根据id删除用户信息
        System.out.println("删除用户信息");
        linkedList.deleteNode(new UserNode(3, ""));
        linkedList.getList();
        System.out.println();

        //获得倒数第几个节点
        System.out.println("获得倒数节点");
        System.out.println(linkedList.getUserByRec(2));
        System.out.println();

        //翻转链表
        System.out.println("翻转链表");
        MyLinkedList newLinkedList = linkedList.reverseList();
        newLinkedList.getList();
        System.out.println();

        //倒叙遍历链表
        System.out.println("倒序遍历链表");
        newLinkedList.reverseTraverse();

    }
}

/**
 * 创建链表
 */
class MyLinkedList {
    private UserNode head = new UserNode(0, "");

    /**
     * 在链表尾部添加节点
     *
     * @param node 要添加的节点
     */
    public void addNode(UserNode node) {
        //创建一个辅助节点,用于遍历
        UserNode temp = head;
        //找到最后一个节点
        while (true) {
            //temp是尾节点就停止循环
            if (temp.next == null) {
                break;
            }
            //不是尾结点就向后移动
            temp = temp.next;
        }
        temp.next = node;
    }

    /**
     * 遍历链表
     */
    public void getList() {
        System.out.println("开始遍历链表");
        if (head.next == null) {
            System.out.println("链表为空");
        }
        //创建辅助节点
        UserNode temp = head.next;
        while (true) {
            //遍历完成就停止循环
            if (temp == null) {
                break;
            }
            System.out.println(temp);
            temp = temp.next;
        }
    }

    /**
     * 按id顺序插入节点
     *
     * @param node
     */
    public void addByOrder(UserNode node) {
        //如果一个节点都没用,直接插入
        if (head.next == null) {
            head.next = node;
            return;
        }
        UserNode temp = head;
        while (temp.next != null && temp.next.id < node.id) {
            temp = temp.next;
        }
        //当目标node的id最大时,则不会执行if中的语句
        if (temp.next != null) {
            node.next = temp.next;
        }
        temp.next = node;
    }

    /**
     * 根据id来修改节点信息
     *
     * @param node 修改信息的节点
     */
    public void changeNode(UserNode node) {
        UserNode temp = head;
        //遍历链表,找到要修改的节点
        while (temp.next != null && temp.id != node.id) {
            temp = temp.next;
        }
        //如果temp已经是最后一个节点,判断id是否相等
        if (temp.id != node.id) {
            System.out.println("未找到该用户的信息,请先创建该用户的信息");
            return;
        }
        //修改用户信息
        temp.name = node.name;
    }

    /**
     * 根据id删除节点,找到待删除节点的上一个节点
     *
     * @param node 要删除的节点
     */
    public void deleteNode(UserNode node) {
        if (head.next == null) {
            System.out.println("链表为空");
            return;
        }
        UserNode temp = head;
        //遍历链表,找到要删除的节点
        while (temp.next != null && temp.next.id != node.id) {
            temp = temp.next;
        }
        //判断最后一个节点的是否要删除的节点
        if (temp.next.id != node.id) {
            System.out.println("请先插入该用户信息");
            return;
        }
        //删除该节点
        temp.next = temp.next.next;
    }

    /**
     * 得到倒数的节点
     *
     * @param index 倒数第几个数
     * @return
     */
    public UserNode getUserByRec(int index) {
        if (head.next == null) {
            System.out.println("链表为空!");
        }
        UserNode temp = head.next;
        //记录链表长度
        //所以length初始化为1
        int length = 1;
        while (temp.next != null) {
            temp = temp.next;
            length++;
        }
        if (length < index) {
            throw new RuntimeException("链表越界");
        }
        //假设有五个,倒数第一个相当于正数第五个
        temp = head.next;
        for (int i = 0; i < length - index; i++) {
            temp = temp.next;
        }
        return temp;
    }

    /**
     * 翻转链表
     *
     * @return 反转后的链表
     */
    public MyLinkedList reverseList() {
        //链表为空或者只有一个节点,无需翻转
        if (head.next == null || head.next.next == null) {
            System.out.println("无需翻转");
        }
        MyLinkedList newLinkedList = new MyLinkedList();
        //用于保存正在遍历的节点
        UserNode temp = head.next;
        //用于保存正在遍历节点的下一个节点
        UserNode nextNode = temp.next;
        while (true) {
            //插入新链表
            temp.next = newLinkedList.head.next;
            newLinkedList.head.next = temp;
            //移动到下一个节点
            temp = nextNode;
            nextNode = nextNode.next;
            if (temp.next == null) {
                //插入最后一个节点
                temp.next = newLinkedList.head.next;
                newLinkedList.head.next = temp;
                head.next = null;
                return newLinkedList;
            }
        }
    }

    public void reverseTraverse() {
        if (head == null) {
            System.out.println("链表为空");
        }

        UserNode temp = head.next;
        //创建栈,用于存放遍历到的节点
        Stack<UserNode> stack = new Stack<>();
        while (temp != null) {
            stack.push(temp);
            temp = temp.next;
        }

        while (!stack.isEmpty()) {
            System.out.println(stack.pop());
        }
    }
}

/**
 * 定义节点
 */
class UserNode {
    int id;
    String name;
    //用于保存下一个节点的地址
    UserNode next;

    public UserNode(int id, String name) {
        this.id = id;
        this.name = name;
    }

    @Override
    public String toString() {
        return "UserNode{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}
点赞
收藏
评论区
推荐文章
22 22
4年前
【数据结构之链表】详细图文教你花样玩链表
【系列文章推荐阅读】0.提要钩玄文章已经介绍了链式存储结构,介绍了链式存储结构的最基本(简单)实现——单向链表。单向链表,顾名思义,它是单向的。因为单链表的每个结点只有一个数据域和一个指针域,而该指针域只存储了下一个结点的地址,所以我们只能通过某结点找到其直接后继结点,却不能通过某节点找到其直接前驱结点。此外,由于单链表到尾结点(链表的最后一
Easter79 Easter79
4年前
tbox链表list和list_entry的使用
TBOX中提供了各种列表操作:1.list:元素在内部维护的双向链表2.list\_entry:元素在外部维护的双向链表3.single\_list:元素在内部维护的单向链表4.single\_list\_entry:元素在外部维护的单向链表由于双链和单链的接口使用类似,这里主要就
Stella981 Stella981
4年前
Redis基本操作——队列 List(原理篇)
Redis基本操作——List(原理篇)  学习过数据结构的同学,一定对链表(LinkedList)十分的熟悉。相信我们自己也曾经使用过这种数据结构。  链表分为很多种:单向链表,双向链表,循环链表,块状链表\1(https://www.oschina.net/action/GoToLink?url
Wesley13 Wesley13
4年前
275,环形链表 II
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回null。为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从0开始)。如果 pos 是 1,则在该链表中没有环。说明:不允许修改给定的链表。示例1:输入:head3,2,0,4,pos
Stella981 Stella981
4年前
LinkedList
Base:JDK1.81、LinkedListLinkedList也是一个比较常见的数据结构,链表。在C/C中,链表也是一个典型的线性结构,链表分为单向跟双向的两种链表。在java里面的LinkedList是一个双向的链表。链表最好的好处就在于来一个数据加一个长度,没有多余的冗余,也是支
Stella981 Stella981
4年前
Linux下V4L2捕捉画面+H264压缩视频+帧缓冲显示视频————结合三个部分工作
前面三篇文章分别介绍了视频捕获、h264视频压缩、帧缓冲显示的实现,现在将他们结合起来摄像头采集到的数据,需要交给视频压缩线程、显示线程使用,那么我采用的方法是使用队列及链表来实现:1.摄像头采集到数据后,分别放入两个处理线程队列中,并将相关信息放入链表中2.两个线程处理完成数据后,调用回调函数,从链表里找到对应的节点,然后释
Stella981 Stella981
4年前
LeetCode 142 环形链表 II python
题目描述给定一个链表,返回链表开始入环的第一个节点。如果链表无环,则返回null。说明:不允许修改给定的链表。样例如果不是环,则输出None如果是环,则输出入口节点想法:通过ac141,知道慢节点循环的次数就是环的长度无环的情况不用考虑,直接返回No
Wesley13 Wesley13
4年前
D1
1\.数据结构  1.1线性结构  (1)最常用的数据结构,特点是数据元素之间存在一对一的线性关系  (2)有两种不同的存储结构,即顺序存储结构和链式存储结构    顺序存储的线性表称为顺序表,顺序表中的存储元素是连续的    链式存储的线性表称为链表,链表中的存储元素不一定是连续的,元素节点中存放数据元素以及相邻元素的地址信息
菜园前端 菜园前端
2年前
什么是链表?
原文链接:什么是链表?链表是有序的数据结构,链表中的每个部分称为节点。可以首、尾、中间进行数据存取,链表的元素在内存中不必是连续的空间,每个节点通过next指针指向下一个节点。优点链表的添加和删除不会导致其余元素位移。缺点无法根据索引快速定位元素。数组和链
深度学习 深度学习
8个月前
头插法实现的树结构:链表式多叉树实现指南
一、简介和特点头插法实现的树是一种使用子节点的多叉。本文实现的树类通过链表头插法高效管理子节点关系,适合需要频繁插入子节点的场景。‌主要特点‌:1.动态子节点管理:使用链表存储子节点1.高效插入:头插法实现O(1)的子节点插入1.泛型支持:模板类设计支持多