首页 > 其他分享 >单向链表的介绍和实现思路

单向链表的介绍和实现思路

时间:2022-09-24 15:44:14浏览次数:82  
标签:temp StudentNode 单向 next 链表 id 思路 节点

链表的介绍

链表在内存中的存储

特点

  • 链表是以节点的方式来存储,是链式存储
  • 每个节点包含 data 域 和 next 域。next域用来指向下一个节点
  • 链表的各个节点不一定是连续存储的
  • 链表分带头节点的链表没有头节点的链表,根据实际的需求来确定

带头结点的逻辑示意图

实现思路

创建(添加)

  • 先创建一个Head头节点,表示单链表的头
  • 后面我们每添加一个节点,就放在链表的最后

遍历

  • 通过一个辅助变量,来遍历整个链表

有序插入

  • 先遍历链表,找到应该插入的位置
  • 要插入的节点的next指向插入位置的后一个节点
  • 插入位置的前一个节点的next指向要插入节点
    • 插入前要判断是否在队尾插入

根据某个属性节点修改值

  • 先遍历节点,找到修改的位置
    • 如果未找到修改节点,则不修改

删除某个节点

  • 先遍历节点,找到要删除节点的前一个节点
  • 进行删除操作

求倒数第n个节点的信息

  • 遍历链表,求出链表的有效长度length(不算头结点)
  • 遍历链表到第length-n的节点

翻转链表

  • 创建一个新的头结点,作为新链表的头
  • 从头遍历旧链表,将遍历到的节点插入新链表的头结点之后
  • 注意需要用到两个暂存节点
    • 一个用来保存正在遍历的节点
    • 一个用来保存正在遍历节点的下一个节点

逆序打印

  • 遍历链表,将遍历到的节点入栈
  • 遍历完后,进行出栈操作,同时打印出栈元素

代码

public class Demo1 {
    public static void main(String[] args) {
        LinkedList linkedList = new LinkedList();
        linkedList.traverseNode();
        System.out.println();
        //创建学生节点,并插入链表
        StudentNode student1 = new StudentNode(1, "Nyima");
        StudentNode student3 = new StudentNode(3, "Lulu");
        linkedList.addNode(student1);
        linkedList.addNode(student3);
        linkedList.traverseNode();
        System.out.println();
 
        //按id大小插入
        System.out.println("有序插入");
        StudentNode student2 = new StudentNode(0, "Wenwen");
        linkedList.addByOrder(student2);
        linkedList.traverseNode();
        System.out.println();
 
        //按id修改学生信息
        System.out.println("修改学生信息");
        student2 = new StudentNode(1, "Hulu");
        linkedList.changeNode(student2);
        linkedList.traverseNode();
        System.out.println();
 
        //根据id删除学生信息
        System.out.println("删除学生信息");
        student2 = new StudentNode(1, "Hulu");
        linkedList.deleteNode(student2);
        linkedList.traverseNode();
        System.out.println();
 
        //获得倒数第几个节点
        System.out.println("获得倒数节点");
        System.out.println(linkedList.getStuByRec(2));
        System.out.println();
 
        //翻转链表
        System.out.println("翻转链表");
        LinkedList newLinkedList = linkedList.reverseList();
        newLinkedList.traverseNode();
        System.out.println();
 
        //倒叙遍历链表
        System.out.println("倒序遍历链表");
        newLinkedList.reverseTraverse();
 
    }
}
 
/**
 * 创建链表
 */
class LinkedList {
    //头节点,防止被修改,设置为私有的
    private StudentNode head = new StudentNode(0, "");
 
    /**
     * 添加节点
     * @param node 要添加的节点
     */
    public void addNode(StudentNode node) {
        //因为头节点不能被修改,所以创建一个辅助节点
        StudentNode temp = head;
        //找到最后一个节点
        while (true) {
            //temp是尾节点就停止循环
            if(temp.next == null) {
                break;
            }
            //不是尾结点就向后移动
            temp = temp.next;
        }
        //现在temp是尾节点了,再次插入
        temp.next = node;
    }
 
    /**
     * 遍历链表
     */
    public void traverseNode() {
        System.out.println("开始遍历链表");
        if(head.next == null) {
            System.out.println("链表为空");
        }
        //创建辅助节点
        StudentNode temp = head.next;
        while(true) {
            //遍历完成就停止循环
            if(temp == null) {
                break;
            }
            System.out.println(temp);
            temp = temp.next;
        }
    }
 
    /**
     * 按id顺序插入节点
     * @param node
     */
    public void addByOrder(StudentNode node) {
        //如果没有首节点,就直接插入
        if(head.next == null) {
            head.next = node;
            return;
        }
        //辅助节点,用于找到插入位置和插入操作
        StudentNode temp = head;
        //节点的下一个节点存在,且它的id小于要插入节点的id,就继续下移
        while (temp.next!=null && temp.next.id < node.id) {
            temp = temp.next;
        }
        //如果temp的下一个节点存在,则执行该操作
        //且插入操作,顺序不能换
        if(temp.next != null) {
            node.next = temp.next;
        }
        temp.next = node;
    }
 
    /**
     * 根据id来修改节点信息
     * @param node 修改信息的节点
     */
    public void changeNode(StudentNode node) {
        if(head == null) {
            System.out.println("链表为空,请先加入该学生信息");
            return;
        }
        StudentNode 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(StudentNode node) {
        if(head.next == null) {
            System.out.println("链表为空");
            return;
        }
        StudentNode temp = head.next;
        //遍历链表,找到要删除的节点
        if(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 StudentNode getStuByRec(int index) {
        if(head.next == null) {
            System.out.println("链表为空!");
        }
        StudentNode temp = head.next;
        //用户记录链表长度,因为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 LinkedList reverseList() {
        //链表为空或者只有一个节点,无需翻转
        if(head.next == null || head.next.next == null) {
            System.out.println("无需翻转");
        }
        LinkedList newLinkedList = new LinkedList();
        //给新链表创建新的头结点
        newLinkedList.head = new StudentNode(0, "");
        //用于保存正在遍历的节点
        StudentNode temp = head.next;
        //用于保存正在遍历节点的下一个节点
        StudentNode 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("链表为空");
        }
 
        StudentNode temp = head.next;
        //创建栈,用于存放遍历到的节点
        Stack<StudentNode> stack = new Stack<>();
        while(temp != null) {
            stack.push(temp);
            temp = temp.next;
        }
 
        while (!stack.isEmpty()) {
            System.out.println(stack.pop());
        }
    }
}
 
/**
 * 定义节点
 */
class StudentNode {
    int id;
    String name;
    //用于保存下一个节点的地址
    StudentNode next;
 
    public StudentNode(int id, String name) {
        this.id = id;
        this.name = name;
    }
 
    @Override
    public String toString() {
        return "StudentNode{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

  

标签:temp,StudentNode,单向,next,链表,id,思路,节点
From: https://www.cnblogs.com/wyh518/p/16725760.html

相关文章

  • 3. 链表
    链表是一种通过指针串联在一起的线性结构,每一个结点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针),最后一个结点的指针域指向null(空指针的意思)。1.链......
  • 算法练习-第三天【链表】
    链表203.移除链表元素参考:代码随想录203.移除链表元素看完题目的第一想法一道基本的链表题目,遍历链表如果当前节点的下一个节点值等于val,那么就将当前节点的Next指......
  • [原创] 主成分分析(PCA)思路梳理
    作者:StevenYang([email protected])读本教程前,假定你的线性代数和概率论数理统计已经学得很好了。在一组多维度的数据中,如果找出他的各个主成分?假如数据是二......
  • 代码随想录day3|203.移除链表元素 707.设计链表 206. 反转链表
    203.移除链表元素题目链接:[https://leetcode.cn/problems/remove-linked-list-elements/submissions/]文章链接:[https://www.programmercarl.com/0203.移除链表元素.ht......
  • 代码随想录第三天| 203.移除链表元素、707.设计链表、206.反转链表
    第一题其实这题我一直不理解为什么明明整个过程没有操作dummy,最后要返回dummy.next,dedug了一下发现是pre.next=cur.next;这一步的时候对dummy进行了更新,之后又看了......
  • 驱动开发:内核中的链表与结构体
    Windows内核中是无法使用vector容器等数据结构的,当我们需要保存一个结构体数组时,就需要使用内核中提供的专用链表结构LIST_ENTRY通过一些列链表操作函数对结构体进行装入弹......
  • leetcode 144. Binary Tree Preorder Traversal 二叉树展开为链表(中等)
    一、题目大意给你二叉树的根节点root,返回它节点值的前序遍历。示例1:输入:root=[1,null,2,3]输出:[1,2,3]示例2:输入:root=[]输出:[]示例3:输入:root=......
  • LeetCode 707.设计链表
    class MyLinkedList {    int size=0;    class Node{        int val;        Node next;        Node prev;      ......
  • 力扣21(java&python)-合并两个有序链表(简单)
    题目:将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。  示例1:输入:l1=[1,2,4],l2=[1,3,4]输出:[1......
  • Leetcode 707 -- 设计链表
    1.题目描述设计一个链表,实现基本操作(增删改查)2.单链表/*============================================someinstructinos:pre:leetcode'sLi......