单链表(Java–尚硅谷)

大体结构和C++的链表差不多

补充之前不知道的:链表分两类,带和不带头结点的链表 现在才知道,Java没有像C/C++那样的指针

首先创建一个 LinkList类,然后把链表的各个功能添加进去

//当不考虑编号顺序时,找到当前链表最后节点,将最后节点next指向新节点
public void add(PersonNode node) {
    //因为头节点不能动,先需要一个辅助遍历节点temp
    PersonNode temp = head;
    while (true) {//遍历链表,找到最后
        if (temp.next == null) {
            break;
        }
        temp = temp.next;//如果没到最后,就继续找下去
    }//当退出while循环时,temp指向链表的最后
    temp.next = node;
}
public void addByOrder(PersonNode node) {
    //因为头节点不移动,仍通过一个辅助变量来找添加的位置
    //因为是单链表,所以找的temp时位于添加位置的前一个结点,否则不能插入
    PersonNode temp = head;
    boolean flag = false;//标识添加的编号是否存在
    while (true) {
        if (temp.next == null) //说明temp在链表最后
            break;
        if (temp.next.no > node.no) {//位置找到了,就在temp后面
            break;
        } else if (temp.next.no == node.no) {//希望添加的编号已存在
            flag = true;
            break;
        }
        temp = temp.next;
    }
    if (flag) {//编号已存在,不能添加
        System.out.println("already exist no." + node.no + ", you can't add it.=====");
    } else {
        node.next = temp.next;
        temp.next = node;
    }
}//最终还是按照序号来排列
public void edit(PersonNode node) {//这里直接引入外部结点,根据node.no来寻找需要修改的结点
    if (head.next == null) {
        System.out.println("empty LinkList====");
        return;
    }
    PersonNode temp;
    temp = head.next;
    boolean flag = false;//判断是否找到该结点
    while (true) {
        if (temp == null)
            break;//到了链表最后
        if (temp.no == node.no) {
            flag = true;//找到
            break;
        }
        temp = temp.next;
    }
    //根据flag判断是否找到
    if (flag) {
        temp.name = node.name;
        temp.score = node.score;
    } else {
        System.out.println("not found no." + node.no + "====");
    }
    System.out.println("=======");
}
public void delete(int no) {
    if (head.next == null) {
        System.out.println("empty LinkList===");
        return;
    }
    PersonNode temp = head;//temp指向待删除结点的前一个结点
    boolean flag = false;
    while (true) {
        if (temp.next == null) {
            break;//已经到链表最后
        }
        if (temp.next.no == no) {
            flag = true;//找到了待删除结点的前一个结点temp
            break;
        }
        temp = temp.next;
    }
    if (flag) {
        temp.next = temp.next.next;
    //Java会自动回收未被访问的数据
    } else {
        System.out.println("not found====");
    }
    System.out.println("====");
}
public void list() {
    //判断链表是否为空
    if (head.next == null) {
        System.out.println("empty LinkList=====");
        return;
    }
    //头节点不动,需要一个辅助变量来遍历
    PersonNode temp = head.next;
    while (true) {
        //判断是否到链表最后
        if (temp == null) {
            break;
        }
        //输出节点信息
        System.out.println(temp);
        //由于之前重写了toString,这里直接打印temp就可以打印出节点的所有信息
        temp = temp.next;
    }
}
public static void main(String[] args) {
    PersonNode person1 = new PersonNode(1, "Jordan", 56);
    PersonNode person2 = new PersonNode(2, "Kobe", 81);
    PersonNode person3 = new PersonNode(3, "James", 61);
    PersonNode person4 = new PersonNode(4, "Melo", 60);
    LinkList list = new LinkList();
//按照顺序添加
    // System.out.println("====add====");
    // list.add(person1);
    // list.add(person2);
    // list.add(person3);
    // list.add(person4);
//不按照顺序添加
    System.out.println("====add by order====");
    list.addByOrder(person1);
    list.addByOrder(person4);
    list.addByOrder(person3);
    list.addByOrder(person2);
    list.list();
    // list.addByOrder(person2);
    System.out.println("====edit====");
    PersonNode newNode = new PersonNode(3, "Ivring", 57);
    list.edit(newNode);
    list.list();
//删除结点
    System.out.println("====delete====");
    list.delete(4);
    list.list();
}
//SingleLinkList.java
public class SingleLinkList {
    public static void main(String[] args) {
        PersonNode person1 = new PersonNode(1, "Jordan", 56);
        PersonNode person2 = new PersonNode(2, "Kobe", 81);
        PersonNode person3 = new PersonNode(3, "James", 61);
        PersonNode person4 = new PersonNode(4, "Melo", 60);
        LinkList list = new LinkList();
    //按照顺序添加
        // System.out.println("====add====");
        // list.add(person1);
        // list.add(person2);
        // list.add(person3);
        // list.add(person4);
    //不按照顺序添加
        System.out.println("====add by order====");
        list.addByOrder(person1);
        list.addByOrder(person4);
        list.addByOrder(person3);
        list.addByOrder(person2);
        list.list();
        // list.addByOrder(person2);
        System.out.println("====edit====");
        PersonNode newNode = new PersonNode(3, "Ivring", 57);
        list.edit(newNode);
        list.list();
    //删除结点
        System.out.println("====delete====");
        list.delete(4);
        list.list();
    }
}
//定义一个成员点
class PersonNode {
    String name;
    public int no;
    public int score;
    public PersonNode next;//指向下一个结点

    public PersonNode(int no, String name, int score) {
        this.no = no;
        this.name = name;
        this.score = score;
    }
    //为了显示方便,重写toString
    @Override
    public String toString() {
        return "[no=" + no + ",name=" + name + ",score=" + score + "]";
    }
}
//定义LinkList管理person
class LinkList {
    //初始化头节点,头节点不能动
    private PersonNode head = new PersonNode(0, "", 0);
    public PersonNode getHead(){
        return head;//返回私有成员head
    }
    //当不考虑编号顺序时,找到当前链表最后节点,将最后节点next指向新节点
    public void add(PersonNode node) {
        //因为头节点不能动,先需要一个辅助遍历节点temp
        PersonNode temp = head;
        while (true) {//遍历链表,找到最后
            if (temp.next == null) {
                break;
            }
            temp = temp.next;//如果没到最后,就继续找下去
        }//当退出while循环时,temp指向链表的最后
        temp.next = node;
    }

    public void addByOrder(PersonNode node) {
        //因为头节点不移动,仍通过一个辅助变量来找添加的位置
        //因为是单链表,所以找的temp时位于添加位置的前一个结点,否则不能插入
        PersonNode temp = head;
        boolean flag = false;//标识添加的编号是否存在
        while (true) {
            if (temp.next == null) //说明temp在链表最后
                break;
            if (temp.next.no > node.no) {//位置找到了,就在temp后面
                break;
            } else if (temp.next.no == node.no) {//希望添加的编号已存在
                flag = true;
                break;
            }
            temp = temp.next;
        }
        if (flag) {//编号已存在,不能添加
            System.out.println("already exist no." + node.no + ", you can't add it.=====");
        } else {
            node.next = temp.next;
            temp.next = node;
        }
    }

    public void edit(PersonNode node) {
        if (head.next == null) {
            System.out.println("empty LinkList====");
            return;
        }
        PersonNode temp;
        temp = head.next;
        boolean flag = false;//判断是否找到该结点
        while (true) {
            if (temp == null)
                break;//到了链表最后
            if (temp.no == node.no) {
                flag = true;//找到
                break;
            }
            temp = temp.next;
        }
        //根据flag判断是否找到
        if (flag) {
            temp.name = node.name;
            temp.score = node.score;
        } else {
            System.out.println("not found no." + node.no + "====");
        }
        System.out.println("=======");
    }

    public void delete(int no) {
        if (head.next == null) {
            System.out.println("empty LinkList===");
            return;
        }
        PersonNode temp = head;//temp指向待删除结点的前一个结点
        boolean flag = false;
        while (true) {
            if (temp.next == null) {
                break;//已经到链表最后
            }
            if (temp.next.no == no) {
                flag = true;//找到了待删除结点的前一个结点temp
                break;
            }
            temp = temp.next;
        }
        if (flag) {
            temp.next = temp.next.next;
        } else {
            System.out.println("not found====");
        }
        System.out.println("====");
        //Java会自动回收未被访问的数据
    }

    //显示链表(遍历)
    public void list() {
        //判断链表是否为空
        if (head.next == null) {
            System.out.println("empty LinkList=====");
            return;
        }
        //头节点不动,需要一个辅助变量来遍历
        PersonNode temp = head.next;
        while (true) {
            //判断是否到链表最后
            if (temp == null) {
                break;
            }
            //输出节点信息
            System.out.println(temp);
            //由于之前重写了toString,这里直接打印temp就可以打印出节点的所有信息
            temp = temp.next;
        }
    }

}
//如果带头节点的链表,不统计头节点
public static int getLength(PersonNode head) {
    if (head.next == null)
        return 0;
    int length = 0;
    PersonNode current = head.next;//定义辅助变量
    while (current != null) {
        length++;
        current = current.next;
    }
    return length;
}

在主函数中测试

System.out.println(getLength(list.getHead()));
  • 编写一个方法,接收head结点,同时接收一个index
  • index表示是倒数第index个结点
  • 先把链表从头到尾遍历,得到链表的总长度 getLength
  • 得到size后,我们从链表第一个开始遍历 (size-index)
public static PersonNode findLastIndexNode(PersonNode head, int index){
    if (head.next == null)
        return null;
    int size = getlength(head);//第一次遍历,获取链表大小
    if (index  size)//判断倒数的序号是否超出容量
        return null;
    PersonNode current = head.next;
    for (int i = 0; i < size - index; i++) {
        current = current.next;//遍历size-index次
    }
    return current;
}
  • 先定义一个结点 reverseHead = new PersonNode();
  • 从头到尾遍历原来的链表,每遍历一个链表,就将其取出,放在新链表最前端
  • 原来链表的 head.next = reverseHead.next;
public static void reverseList(PersonNode head) {
    if (head.next == null || head.next.next == null)
        return;
    // 定义一个辅助遍历,帮助遍历原来的链表
    PersonNode current = head.next;
    PersonNode next = null;//指向当前结点[current]的下一个结点
    PersonNode reverseHead = new PersonNode(0, "", 0);
    while (current != null) {
        next = current.next;//先暂时保存当前结点的下一个结点,后面会用到
        current.next = reverseHead.next;//把current的下一个结点指向新链表最前端
        reverseHead.next = current;//将current连接到新链表
        current = next;//让current后移
/*每一次循环,reverseHead.next都会按照原链表的顺序定位到current,遍历结束,刚到reverseHead.next定位到链表最后一个,
此时把reverseHead.next地址赋给head.next,这样就可以倒着来遍历链表*/

    }
    head.next = reverseHead.next;//头结点拼接,实现反转
}
reverseList(list.getHead());
list.list();
  • 1.先反转后再打印(有个问题:只要求逆序打印,不要求反转,这样会破坏原链表结构)
  • 2.用栈的方法,利用栈先进后出的特点,实现逆序打印的效果

stack.java

下面是栈的实例

import java.util.Stack;
public class stack{
    public static void main(String[] args){
        Stack stack = new Stack<>();
        stack.add("James");
        stack.add("Kboe");
        stack.add("Jordan");
        while(stack.size() > 0){
            System.out.println(stack.pop());
        }
    }
}

用栈的方法实现从头到尾打印单链表

public static void reversePrint(PersonNode head) {
    if (head.next == null)
        return;
    //创建一个栈,将各个结点压入栈
    Stack stack = new Stack();
    PersonNode current = head.next;
    while (current != null) {
        stack.push(current);
        current = current.next;
    }
    while (stack.size() > 0) {
        System.out.println(stack.pop());
    }
}
reversePrint(list.getHead());

Original: https://www.cnblogs.com/jaydenchang/p/15114148.html
Author: JaydenChang
Title: 单链表(Java–尚硅谷)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/585170/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • HttpClient的 java.net.SocketException: Too many open files

    今天在维护一个老项目的时候发现,错误: 大致意思是,资源未释放。 代码用的是httpClient,在finally中也关比了资源 后来找度娘了解下: 所以,我的:postMetho…

    Java 2023年5月29日
    0168
  • 如何生成一个java文档

    如何生成一个java文档 众所周知,一个程序给别人看可能可以看懂,几万行程序就不一定了。在更多的时候,我们并不需要让别人知道我们的程序是怎么写的,只需要告诉他们怎么用的。那么,ap…

    Java 2023年6月9日
    081
  • Sonarqube安装(Docker)

    一,拉取相关镜像并运行 拉取sonarqube镜像 docker pull sonarqube:9.1.0-community 在运行之前要提前安装postgres并允许,新建数据…

    Java 2023年6月15日
    087
  • ClickHouse性能优化?试试物化视图

    一、前言 ClickHouse是一个用于联机分析(OLAP)的列式数据库管理系统(DBMS);目前我们使用CH作为实时数仓用于统计分析,在做性能优化的时候使用了 &#x72…

    Java 2023年6月6日
    0102
  • 【翻译】Spring Security-如何解决WebSecurityConfigurerAdapter类已被弃用的问题?

    原文发表日期:2022年6月1日 在这篇短文中,我想分享如何在使用Spring Security的Spring应用中避免” WebSecurityConfigurerA…

    Java 2023年6月6日
    059
  • 技能篇:实际开发常用设计模式

    创建型 单例模式 单例对象能节约系统资源,一个对象的创建和消亡的开销可能很小。但是日常的服务接口,就算是一般小公司也有十几万的QPS吧。每一次的功能运转都创建新的对象来响应请求,十…

    Java 2023年6月5日
    086
  • 关于非对称加密的一点解说

    非对称加密定义: 非对称加密算法又称 &#x73B0;&#x4EE3;&#x52A0;&#x5BC6;&#x7B97;&#x6CD5…

    Java 2023年6月16日
    0105
  • java基础4.19

    1.JAVA 的反射机制的原理。JAVA反射机制是在运行状态中,对于 任意一个类,都能够 知道这个类的 所有属性和方法;对于任意一个对象,都能够调 用它的任意一个方法;这种 动态获…

    Java 2023年6月5日
    064
  • JDBC&数据库连接池

    1、JDBC简介 JDBC 就是使用Java语言操作关系型数据库的一套API全称:( Java DataBase Connectivity ) Java 数据库连接 JDBC是使用…

    Java 2023年6月13日
    061
  • spring boot jdbctemplate queryforstream 使用问题

    开发一个功能为了避免内存问题,使用了 jdbctemplate queryforstream,同时日常中会使用链接池,运行一段时间会出现链接超时的问题 参考示例代码 @RestCo…

    Java 2023年5月30日
    078
  • JS input输入框字数超出长度显示省略号…..

    样式添加: overflow:hidden; white-space:nowrap; text-overflow:ellipsis; Original: https://www.c…

    Java 2023年6月9日
    073
  • 木马免杀

    最近学了点木马免杀,其实总结起来一共有三个层面,代码面,文件面,逻辑面。 代码层面可以通过shellcode编码混淆,编辑执行器,分离加载器等方法进行免杀 文件面可以通过特征码定位…

    Java 2023年6月6日
    061
  • RestTemplate–解决中文乱码

    【原文链接】:https://blog.tecchen.xyz ,博文同步发布到博客园。由于精力有限,对文章的更新可能不能及时同步,请点击上面的原文链接访问最新内容。欢迎访问我的个…

    Java 2023年6月6日
    074
  • 从 KeyStore 中获取 PublicKey 和 PrivateKey

    KeyStore(译:密钥存储库) 代表用于加密密钥和证书的存储设施。 KeyStore 管理不同类型的 entry(译:条目)。每种类型的 entry 都实现了 KeyStore…

    Java 2023年6月7日
    083
  • launchMode(启动模式)

    默认启动模式,每次将创建一个新的实例。 如果该活动处于栈顶部,则不会新建实例,否则新建实例; 复用时会触发 onNewIntent 方法。 栈内唯一,只要栈中存在该实例,将被复用;…

    Java 2023年6月7日
    089
  • Python面向对象

    1.面向对象 2.什么是类和类变量? 3.实例和实例化以及实例变量 4.数据成员 5.方法和静态方法以及类方法 6.什么是方法重写 7. _ init _ 8.self 9.类的初…

    Java 2023年6月7日
    076
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球