数据结构——单链表与双链表(java实现)

news2024/9/22 1:27:31

文章目录

  • 前言
    • 链表:
    • 链表分类:
  • 一 单链表
    • 单链表的实现:
    • 节点的实现
    • 头插法:
    • 尾插法
    • 在任意位置插入数据:
    • 查找单链表中是否有key关键字(即是否有值为key的数据)
    • 删除第一次出现的关键字为key的节点
    • 删除所有值为key的节点
    • 获取单链表的长度
    • 清空链表
    • 单链表的优缺点:
  • 二、双链表
    • 双向链表的实现:
    • 内部类实现节点
    • 头插法:
    • 尾插法:
    • 任意位置插入数据
    • 查找是否关键字key是否在双链表当中
    • 删除第一次出现关键字为key的节点
    • 删除所有值为key的节点
    • 得到链表的长度
    • 清空链表
  • java提供的LinkedList接口
    • 实现的接口:
    • 构造方法
    • 关于java提供的LinkedList方法的使用
      • 常用的方法有这几种:
      • 关于链表的遍历
    • 双向链表的优缺点
    • ArrayList和LinkedList对比


前言

链表:

链表是线性表的一种,在物理存储结构上不一定连续(绝大多数情况下非连续),在数据逻辑顺序上,将节点用指针链接起来实现连续。
链表是由一个一个的节点组成

在这里插入图片描述
节点:节点中分为数据域与指针域,数据域用于存放数据,指针域用于存放下一个节点的引用地址。
在这里插入图片描述

链表分类:

在这里插入图片描述
所谓带头是指链表中有一个固定的头结点,此头结点携带的数据无效(类似于火车的火车头不承载乘客一样。)
所谓单向是指:链表的头结点可以通过指针遍历到尾结点,但不能够从尾结点遍历到头结点。
如图:
在这里插入图片描述

相应的,双向链表则既可以从头遍历到尾结点,又可以从尾结点遍历到头结点。
如图:
在这里插入图片描述

所谓循环是指尾结点的指针指向头结点
在这里插入图片描述

下面所学的单链表与双链表分别是不带头单向非循环链表与不带头双向非循环链表。

一 单链表

单链表的实现:

在java中实现一个单链表通过定义一个类来实现:

public class  MySingleList {


   public Node head;  //创建指向链表头结点的指针,注意此时的head节点与带头链表的头不同,此时head
   //指向节点的值是有效的

    //关于链表中的方法
    //头插法
    public void addFirst(int data);
    //尾插法
    public void addLast(int data);
    // 任意位置插入,第一个节点为0号下标
    public void addIndex(int index,int data);
    //判断指定数据关键字是否在单链表中
    public boolean contains(int key);
    //删除链表中第一次出现关键字key的节点
    public  void remove(int key);
    //删除所有值为key的节点
    public void removeAllkey(int key);
    //得到单链表的长度
    public int  size();
    //清空单链表
    public void clear();
    //展示单链表
    public void display();
}

节点的实现

节点是一个独立的对象,在java中也通过类来实现,节点是单链表的一部分,所以我们在链表类中定义一个内部类来实现节点。

static class Node
    {
        public   int data; //用于存放数据
        public Node next; //用于存放地址

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

头插法:

思路:将新创建节点的指针(next)指向头(head),再改头为当前节点。
即使head的值为null ,即链表为空,此代码也不会有问题。

  public void addFirst(int data) {
            Node cur = new Node(data);
            cur.next = head;
            head = cur;
        
    }

尾插法

思路:先判断链表是否为空(即head是否为null),如果为空,,则使得头指针head指向新的节点
如果不为空,则找到尾结点,再将尾结点的next指针指向新建节点。

public void addLast(int data) {
        //尾插法:
      
        //头节点是否为空,
        if(head == null){
            head = new Node(data);
        }else {
            Node cur = head;
            //找到链表中最后一个节点
            while (cur.next!=null){
                cur = cur.next;
            }
            //找到最后一个节点后,进行尾插
            cur.next = new Node(data);
        }
    }

在任意位置插入数据:

  1. 先判断指定下标index是否合法。
  2. 如果index为0,则采取头插法,如果index为链表长度即链表末尾,则采取尾插法
  3. 如果是中间节点,保存插入位置的前一个节点地址,改动前一个节点的next与插入节点的next值
  public void addIndex(int index, int data) {
        //需要判断index的值是否合法。
        if(index>size()||index<0){
            System.out.println("index的值不合法");
            return;
        }
           if(index ==0) {
               //如果index处于顺序表的头节点处
               addFirst(data);
               return;
           }
            //如果index处于顺序表末尾的后一位
            if (index ==size()){
                //则直接调用addLast方法即可
                addLast(data);
                return ;
                }
            if(index>0&&index<size()){
                //进行中间插入,需要找到插入位置的前一个节点,找到插入位置
                Node cur = head;
                while(index>1){
                    cur = cur.next;
                    index--;
                }
                //此为插入位置的前一个节点
                Node prev = cur;
                //此为插入位置的节点
                cur = prev.next;
                //创建一个新的节点并插入:
                Node cur2 = new Node(data);
                cur2.next =cur;
                prev.next = cur2;
                return;
            }
        }

查找单链表中是否有key关键字(即是否有值为key的数据)

思路:直接遍历即可。

 public boolean contains(int key) {
        //判断链表中是否包含关键字
        Node cur = head;
        while (cur!= null){
            if (cur.data == key){
                return true;
            }
            cur = cur.next;
        }
        return false;
    }

删除第一次出现的关键字为key的节点

思路1:

  1. 先判断链表是否为空,空直接返回
  2. 链表不为空时,遍历链表,当出现关键字key时,判断是否为头结点,如果是则head指向头结点的下一个节点
  3. 如果关键字不是头结点的数据,则让前一个节点的下一个节点置为当前节点的下一个节点;

思路2:也可以将涉及头结点的算法整理到一边,即如果头结点为null与头结点的值为key的情况,然后再处理第一次出现的key为中间节点的情况,这样看起来代码更简洁。

思路1 :

public void remove(int key) {
        if(head ==null){
            return;
        }
        //移除第一次出现的关键字key
        Node cur = head;
        Node prev = cur;
        while (cur!=null){
            if(cur.data ==key){
                //如果此时cur节点为头节点
             if(cur ==head){
                 head = head.next;
                 return;
             }else {
                 //如果此时cur节点是非头节点
                 prev.next = cur.next;
                 return;
             }
            }
            prev = prev.next;
            cur = cur.next;
        }
    }

思路2:

public void remove(int key){
        if(head == null){
            return;
        } else if (head .data == key) {
            head = head.next;
            return;
        }
        Node cur = head.next;
        Node prev = head;

        while(cur != null){
            if(cur.data == key){
                prev.next = cur.next;
                return;
            }
            prev = prev.next;
            cur = cur.next;
          
        }
    }

删除所有值为key的节点

思路:只采用一次遍历,便将所有指定的节点删除
与删除一个节点的算法思想2大致相同.

public void removeAllKey(int key){
        if(head == null){
            return;
        } //这里不需要再加head.data =key的情况,因为下方已经有了这个语句,
        Node cur = head.next;
        Node prev = head;

        while(cur != null){
            if(cur.data == key){
                prev.next = cur.next; //祛除了prev.next对cur节点的引用
                cur = cur.next;

            }else {
                cur = cur.next;
                prev = prev.next;
            }
        }
        if(head.data == key){
            head = head.next;
        }
    }

如果将头结点删除与中间节点,尾结点删除混合在一起,算法就会麻烦与复杂很多。

获取单链表的长度

  public int  size() {
       int count = 0;
       Node cur = head;
       while (cur!=null){
           count++;
           cur = cur.next;

       }
       return count;
    }

清空链表

思想1:通过遍历链表,将头结点的值不断后移,最终将链表置为空(头结点后移中,没有引用指向前面的节点,前面的节点自动被回收)
思想2:也可以不移动头,遍历链表,将每个节点的next指针置为null,最后将头指针置为null,这种方法麻烦一些

思想1:

public void clear(){
        Node cur = head;
        while (cur != null){
            head = cur.next;
            //不用将cur =null ,因为系统回收堆区的条件是没有引用引用这块空间。
            cur = head;
        }
    }

思想2:

public void clear() {
           //清空链表
        Node cur= head;
        while (cur!=null){
            Node curN = cur; //将当前节点赋给curN
            cur = cur.next;    //指针后移
            curN.next  = null; //将当前节点的next值置为空
        }
     //最后头结点再置为null
        head = null;
    }

单链表的优缺点:

优点:单向链表增加删除节点简单。
缺点:只能找到后继节点,不能找到前驱节点,只能从前往后遍历,不可以从后往前遍历。

二、双链表

在java集合类中使用的链表是无头双向非循环链表,使用的不是单链表。
在这里插入图片描述

双向链表的实现:

public class MyLinkedList {
    public ListNode head; //指向链表的首结点(此节点的数据是有效的)
    public ListNode last;//指向链表的尾结点
     //头插法
     public void addFirst(int data);
     //尾插法
     public void addLast(int data);
     //任意位置插入,第一个数据节点为0号下标
     public boolean addIndex(int index,int data);
     //查找是否包含关键字key是否在单链表当中
     public boolean contains(int key);
     //删除第一次出现关键字为key的节点
     public void remove(int key);
     //删除所有值为key的节点
     public void removeAllKey(int key);
     //得到链表的长度
     public int size();
     //情空链表
     public void clear();
 }

内部类实现节点

  static class ListNode{
         int data;
         ListNode next; //指向下一个节点
         ListNode prev;//指向前一个节点

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

头插法:

实现思想:

  1. 如果头结点为空,则将head与last指针指向新的节点
  2. 如果不为空则将新的节点的下一个节点置为头结点
  3. 头结点的前一个节点置为新节点, 然后将新节点的引用赋给head.
    public void addFirst(int data){
             //双向链表的头插
            //两种情况:1 头结点为空,2.头结点不为空、
             ListNode cur = new ListNode(data);
             if(head ==null){
                 last = head = cur;
             }else {
                 //如果头结点不为空
                 cur.next = head;
                 head.prev = cur;
                 head = cur;
             }
         }

尾插法:

实现思想:先判断链表是否为空,

  1. 如果为空,则直接将新节点的引用赋给head与last
  2. 如果不为空,则将last的下一个节点置为新节点,新节点的前一个节点置为last,最后由last引用新节点。
     public void addLast(int data){
             //先找到尾结点
            ListNode cur = new ListNode(data);
             if(head == null){
                 last = head = cur;
                 return;
             }
          //有了last指针,便不再需要遍历链表了
             //如果链表不为空:
             last.next = cur;
             cur.prev = last;
             last  = cur;
         }

任意位置插入数据

实现思路:

  1. 判断位置是否合法,不合法直接返回
  2. 插入位置为头节点,对应调用头插方法,是尾结点则采用尾插方法。
  3. 插入位置为中间节点,找到插入位置为对应节点,将插入节点前驱prev改为对应节点前驱,对应节点前驱改为插入节点,插入节点后继next改为对应节点。
    public void addIndex(int index,int data){
             //先判断index值是否合法
             if(index<0||index>size()){
                 System.out.println("index值不合法");
                 return;
             }

             if(index ==0){
                 addFirst(data);
                 return;
             }
             if(index ==size()){
                 addLast(data);
                 return ;
             }
             if(index>0&&index<size()){
                   //中间插入
                 ListNode cur = head;
                 while(index>0){
                     //先找到cur位置
                     cur =cur.next;
                     index--;
                 }
                 ListNode curN = new ListNode(data);
                 //将插入的节点与左右两边的节点相连
                 curN.next = cur;
                 curN.prev = cur.prev;
                 curN.prev.next = curN;
                 cur.prev = curN;

                    return ;
             }
         }

查找是否关键字key是否在双链表当中

实现思想:直接遍历即可

   public boolean contains(int key){
             //判断关键字key是否在双链表中
             ListNode cur = head;

             while (cur!=null){
                 if(cur.data == key){
                     return  true;
                 }
                 cur =cur.next;
             }
             return  false;
         }

删除第一次出现关键字为key的节点

实现思想:

  1. 首先遍历链表,判断第一个关键字key出现的位置
  2. 如果是头结点,则将下一个节点的prev指针置为null,然后head指针指向下一个节点
  3. 如果是其他节点,先执行前一个节点的next指针指向当前节点的下一个节点,然后判断此节点是否为尾结点,如果是,last指针指向的前一个节点,
  4. 不是则将下一个节点的prev指针指向当前节点的前一个节点
  public void remove(int key) {
            
             ListNode cur = head;
             while (cur != null) {
                 if (cur.data == key) {
                     //需要判断此节点是什么节点
                     if (cur == head) {
                         cur.next.prev = null;
                         head = head.next;
                         return;
                     } else {
                         cur.prev.next = cur.next;
                         if (cur == last) {
                             last = last.prev;
                             return;
                         } else {
                             cur.next.prev = cur.prev;
                             return;
                         }
                     }
                 }
                 cur = cur.next;
             }
         }

删除所有值为key的节点

实现思想:与删除一个节点的思路相同,不进行返回,使其循环即可

 public void removeAllKey(int key) {
              ListNode cur = head;

              while (cur != null) {
                  if (cur.data == key) {
                      //需要判断此节点是什么节点
                      if (cur == head) {
                          cur.next.prev = cur.prev;
                          head = head.next;
                      }else {
                          cur.prev.next = cur.next;
                          if(cur ==last){
                              last =last.prev;
                          }else {
                              cur.next.prev = cur.prev;
                          }
                      }
                  }
                  cur =cur .next;
              }
          }

得到链表的长度

思想:直接遍历

     public int size(){
             ListNode cur = head;
             int count = 0;
             while (cur !=null){
                 count++;
                 cur = cur.next;
             }
             return count;
         }

清空链表

实现思想:先将每一个节点的prev指针与next指针置为null,最后清空head与last指针

             ListNode cur = head;
             while(cur !=null){
                 ListNode curN = cur.next;
                 cur.prev = null;  //是将当前节点中的两个指针域置为空,此时cur.prev是本指针置为空,而不是cur.prev指向的节点为空
                                          //要用辩证思维看待,而不是形式逻辑
                 cur.next = null;
                 cur =curN;
             }
            //当遍历完毕后,头结点与尾节点还有引用指向
            
            head = last = null;
    }
}

java提供的LinkedList接口

实现的接口:

在这里插入图片描述
说明:

1 . LinkedList没有实现RandomAccess接口,因此LinkedList不支持随机访问。
2. 实现了Cloneable接口,支持克隆

构造方法

在这里插入图片描述
对于第二种构造方法的参数在EE初阶时,会讲到。

关于java提供的LinkedList方法的使用

常用的方法有这几种:

在这里插入图片描述

关于链表的遍历

在java提供的LinkedList类中并没有提供display方法,遍历的方式有以下几种:
方法1 :直接使用sout打印,因为toString方法被重写了

  public static void main(String[] args) {
        //关于双向链表的使用
        LinkedList<Integer> linkedList = new LinkedList<Integer>();
        linkedList.addLast(1);
        linkedList.addLast(2);
        linkedList.addLast(3);
        linkedList.addLast(4);
        //此时toString方法一定被重写了
        System.out.println(linkedList);
}

方法二:通过for语句或者foreach语句遍历打印

 System.out.println(".........通过for语句............");
        for (int i = 0; i < linkedList.size(); i++) {
            System.out.print(linkedList.get(i));
        }
        System.out.println();
        System.out.println("...........通过foreach语句........");
        for (  Integer i :linkedList) {   //遍历linkedList中的数据,依次放入到变量i当中去
            System.out.print(i);
        }

方法三: 通过迭代器 iterator 打印
迭代器可以遍历链表,通过linkedList.iterator()方法获取一个迭代器对象
然后调用对象的it.hasNext方法,与it.next()方法

it.hasNext方法用于判断it指向的位置是否还有下一个数据,
it.next()方法用于获取it的下一个数据,并且将it往后移动一步。

linkedList.iterator()用于获取一个迭代器对象
在这里插入图片描述

   System.out.println(".........Iterator迭代器..........");
        Iterator <Integer>it  =  linkedList.iterator();
        while (it.hasNext()){ //如果有下一个数据
            System.out.print(it.next() + "  "); //则打印下一个数据,it.next()方法同时会使中的it向后走一步,指向下一个数据
        }
        System.out.println();

ListIterator 类
ListIterator是继承自Iterator,是其子类
在这里插入图片描述
可以看做专门用于链表的迭代器

   System.out.println("..........ListIterator迭代器...........");

        //他继承Iterator类
        ListIterator <Integer>it2   =     linkedList.listIterator();
        while (it2.hasNext()){
            System.out.print(it2.next() + "  ");
        }
        System.out.println();

关于linkedList中listInterator重写的方法:
此方法可以在指定位置开始进行遍历:
在这里插入图片描述

  System.out.println("........重写后的方法,从指定位置开始打印.......");
     //关于linkedList中listInterator重写的方法
        ListIterator <Integer>it3   =     linkedList.listIterator(2);
        while (it3.hasNext()){
            System.out.print(it3.next() + "  ");
        }
        System.out.println();

迭代器不仅可以正向遍历,还可以反向遍历,将迭代器中的it.hasNext,it.next方法替换成
it.hasPrevious与it.previous方法即可

    //也可以从后往前打印
                                                     //事先指定位置,因为头结点前没有数据
        ListIterator <Integer> it4 = linkedList.listIterator(linkedList.size());
      
        while (it4.hasPrevious()){
            System.out.print(it4.previous() + "  ");
        }

在这里插入图片描述

双向链表的优缺点

优点:相对于单链表,可以访问到前驱节点,极其便利
缺点:多耗费了一个指针域,且在删除与插入节点时,指针操作麻烦。

ArrayList和LinkedList对比

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1927531.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深度解析:如何优雅地删除GitHub仓库中的特定commit历史

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

2024.7.15 csp-j第一场模拟赛赛后总结

题目&#xff1a; T1&#xff1a;P1211 [USACO1.3] 牛式 Prime Cryptarithmhttps://www.luogu.com.cn/problem/P1211 T2&#xff1a;P2035 [USACO08JAN] iCow Bhttps://www.luogu.com.cn/problem/P2035 T3&#xff1a;P6207 [USACO06OCT] Cows on Skates Ghttps://www.luogu…

CUDA cuDNN和pytorch(GPU版)的完整安装教程

​ * 说明: 本教程使用wsl-ubuntu20.04, 其他发行版linux的命令可能有所区别. *实测机型: i5-13500HX | RTX 4060 Laptop 一、下载CUDA12.X版本 这里以下载CUDA12.2为例。 前往cuda-12.2下载页, 按照如图方式选择合适的选项&#xff1a; 按照官方给出的命令&#xff0c; 在b…

《昇思25天学习打卡营第22天|基于MindSpore的GPT2文本摘要》

#学习打卡第22天# 1. 数据集 1.1 数据下载 使用nlpcc2017摘要数据&#xff0c;内容为新闻正文及其摘要&#xff0c;总计50000个样本。 from mindnlp.utils import http_get from mindspore.dataset import TextFileDataset# download dataset url https://download.mindspor…

leetcode-349.两个数组的交集

题源 349.两个数组的交集 题目描述 给定两个数组 nums1 和 nums2 &#xff0c;返回 它们的 交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。 示例 1&#xff1a; 输入&#xff1a;nums1 [1,2,2,1], nums2 [2,2] 输出&#xff1a;[2] 示例…

深度解读昇腾CANN模型下沉技术,提升模型调度性能

AI模型的运行通常情况下需要CPU和NPU&#xff08;昇腾AI处理器&#xff09;等AI专用处理器协同工作&#xff0c;CPU所在位置称为主机端&#xff08;Host&#xff09;&#xff0c;而NPU所在位置称为设备端&#xff08;Device&#xff09;。对于采用Host调度的AI模型来说&#xf…

金蝶云星空与金蝶云星空对接集成付款单查询打通[标准][付款单新增]-v1

金蝶云星空与金蝶云星空对接集成付款单查询打通[标准][付款单新增]-v1 对接源平台:金蝶云星空 金蝶K/3Cloud在总结百万家客户管理最佳实践的基础上&#xff0c;提供了标准的管理模式&#xff1b;通过标准的业务架构&#xff1a;多会计准则、多币别、多地点、多组织、多税制应用…

vitest 单元测试应用与配置

vitest 应用与配置 一、简介 Vitest 旨在将自己定位为 Vite 项目的首选测试框架&#xff0c;即使对于不使用 Vite 的项目也是一个可靠的替代方案。它本身也兼容一些Jest的API用法。 二、安装vitest // npm npm install -D vitest // yarn yarn add -D vitest // pnpm pnpm …

CoT-SC论文速读

1.论文速读 本文提出了一个重要的Decoder策略为&#xff1a;“Self-Consistency”,并将其用在CoT的Prompt工作中。 该策略作用&#xff1a;让LLM在处理复杂问题时&#xff0c;让他尝试多个推理路径&#xff0c;每一个推理路径都是一次CoT&#xff08;Chain of Thought&#x…

构建实用的NLP应用程序:重塑人类与计算机的协同工作方式

文章目录 一、NLP技术的核心价值二、构建实用NLP应用程序的关键步骤三、NLP应用程序在协同工作中的创新应用《赠ChatGPT中文范例的自然语言处理入门书》编辑推荐内容简介作者简介精彩书评目录前言/序言获取方式 在数字化时代&#xff0c;自然语言处理&#xff08;NLP&#xff0…

哥德巴赫猜想c++

方法一 #include<bits/stdc.h> using namespace std; //定义函数&#xff0c;判断素数 bool sushu(int n){bool rtrue;//先假设是素数&#xff0c;即真//循环因子范围&#xff0c;找到一个因子就不是素数for(int i2;i<sqrt(n);i){//判断2~n的根号是否素数if(n%i0){//…

码住!热门且创新idea:GNN+强化学习!

如何提高学习效率、优化策略&#xff0c;并解决复杂的图结构相关问题&#xff1f;或许你可以考虑&#xff1a;GNN强化学习。 GNN结合强化学习是当前的热门创新方向&#xff0c;它通过利用GNN在图形数据上的强大表示能力与强化学习在决策制定中的优势&#xff0c;不仅能够有效处…

鸿蒙语言基础类库:【@ohos.uitest (UiTest)】 测试

UiTest UiTest提供模拟UI操作的能力&#xff0c;供开发者在测试场景使用&#xff0c;主要支持如点击、双击、长按、滑动等UI操作能力。 该模块提供以下功能&#xff1a; [By]&#xff1a;提供控件特征描述能力&#xff0c;用于控件筛选匹配查找。[UiComponent]&#xff1a;代…

中电金信:成功的智慧运营转型,重点是把握“一个基本点和两大主线”

“运营”是银行不可或缺的基础职能&#xff0c;负责产品的服务交付过程和业务的落地处理&#xff0c;解决商业模式下“怎么做”的问题。纵观全球领先银行的运营转型历程&#xff0c;已从传统分散运营逐步转向集中运营、共享运营&#xff0c;乃至价值创造。从国内银行运营转型发…

微信小程序毕业设计-青少年科普教学系统项目开发实战(附源码+论文)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;微信小程序毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计…

基于SpringBoot协同过滤算法商品推荐系统(源码+lw+部署文档+讲解等)

前言&#xff1a; 博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术范围&#xff1a;SpringBo…

C++面试问题

C基础 什么是野指针&#xff1f; 指向未分配或已释放内存的指针。比如未初始化、delete后未指向空、保存了局部变量的地址 怎么解决野指针问题&#xff1f; 使用智能指针释放后置空指针初始化避免返回局部变量的地址 C空类会创造那些函数&#xff1f; 默认构造析构函数拷…

【qt】TCP客户端如何断开连接?

disconnectFromHost() 来关闭套接字,断开连接. 当我们关闭窗口时,也需要断开连接. 需要重写关闭事件 如果当前的套接字状态是连接上的,我们就可以来断开连接. 运行结果:

空安全编程的典范:Java 8中的安全应用指南

文章目录 一、Base64 编码解码1.1 基本的编码和解码1.2 URL 和文件名安全的编码解码器1.3 MIME Base64编码和解码 二、Optional类三、Nashorn JavaScript 一、Base64 编码解码 1.1 基本的编码和解码 Base64 编码&#xff1a; 使用 Base64.getEncoder().encodeToString(origin…