「Java 数据结构全面解读」:从基础到进阶的实战指南

「Java 数据结构全面解读」:从基础到进阶的实战指南

数据结构是程序设计中的核心部分,用于组织和管理数据。Java 提供了丰富的集合框架和工具类,涵盖了常见的数据结构如数组、链表、栈、队列和树等。本文将系统性地介绍这些数据结构的概念、特点以及在 Java 中的实现,并通过代码示例进行演示。


一、数据结构基础概念

数据结构研究的是数据的逻辑结构和物理结构,以及它们之间的关系。

1.1 数据的逻辑结构

数据的逻辑结构反映了数据元素之间的逻辑关系,而与存储位置无关。常见逻辑结构包括:

  • 散列结构:元素之间除了“同属一个集合”外,没有其他关系。
  • 线性结构:元素之间存在一对一的关系,例如数组、链表。
  • 树形结构:元素之间存在一对多的关系,例如二叉树。
  • 图形结构:元素之间存在多对多的关系。

在这里插入图片描述

1.2 数据的物理结构

数据的物理结构描述了数据在计算机内存中的存储方式,主要有:

  • 数组结构:元素在内存中是连续存储的,即元素存储在一整块连续的存储空间中,此时根据索引的查询效率是非常高的,因为可以根据下标索引直接一步到位找到元素位置,如果在数组末尾添加和删除元素效率也非常高。缺点是,如果事先申请足够大的内存空间,可能造成空间浪费,如果事先申请较小的内存空间,可能造成频繁扩容导致元素频繁搬家。另外,在数组中间添加、删除元素操作,就需要移动元素,此时效率也要打折。
  • 链式结构:元素在内存中是不要求连续存储的,但是元素是封装在结点当中的,结点中需要存储元素数据,以及相关结点对象的引用地址。结点与结点之间可以是一对一的关系,也可以一对多的关系,比如:链表、树等。遍历链式结构只能从头遍历,对于较长的链表来说查询效率不高,对于树结构来说,查询效率比链表要高一点,因为每次可以确定一个分支,从而排除其他分支,但是相对于数组来说,还是数组[下标]的方式更快。树的实现方式有很多种,无非就是在添加/删除效率 与 查询效率之间权衡。
  • 索引结构:元素在内存中是不要求连续存储的,但是需要有单独的一个索引表来记录每一个元素的地址,这种结构根据索引的查询效率很高,但是需要额外存储和维护索引表。。
  • 哈希结构:元素的存储位置需要通过其hashCode值来计算,查询效率也很多,但是要考虑和解决好哈希冲突问题。

数据结构和算法是一门完整并且复杂的课程
在这里插入图片描述

二、Java 中常见的数据结构实现

Java 提供了丰富的数据结构支持,包括动态数组、链表、栈、队列和树等。这些数据结构主要通过 java.util 包中的类实现。

2.1 数组

动态数组特点

逻辑结构特点:线性结构

物理结构特点:
  • 申请内存:一次申请一大段连续的空间,一旦申请到了,内存就固定了。
  • 存储特点:所有数据存储在这个连续的空间中,数组中的每一个元素都是一个具体的数据(或对象),所有数据都紧密排布,不能有间隔。
例如:整型数组

在这里插入图片描述

例如:对象数组

在这里插入图片描述

自定义动态数组(拓展)示例代码
package com.test.list;

import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;

public class MyArrayList<E> implements Iterable<E>{
    private Object[] all;
    private int total;

    public MyArrayList(){
        all = new Object[10];
    }

    public void add(E e) {
        ensureCapacityEnough();
        all[total++] = e;
    }

    private void ensureCapacityEnough() {
        if(total >= all.length){
            all = Arrays.copyOf(all, all.length + (all.length>>1));
        }
    }

    public void insert(int index, E value) {
        //是否需要扩容
        ensureCapacityEnough();
        //添加元素的下标检查
        addCheckIndex(index);
        if(total-index > 0) {
            System.arraycopy(all, index, all, index+1, total-index);
        }
        all[index]=value;
        total++;
    }

    private void addCheckIndex(int index) {
        if(index<0 || index>total){
            throw new IndexOutOfBoundsException(index+"越界");
        }
    }

    public void delete(E e) {
        int index = indexOf(e);
        if(index==-1){
            throw new NoSuchElementException(e+"不存在");
        }
        delete(index);
    }

    public void delete(int index) {
        //删除元素的下标检查
        checkIndex(index);
        if(total-index-1 > 0) {
            System.arraycopy(all, index+1, all, index, total-index-1);
        }
        all[--total] = null;
    }

    private void checkIndex(int index) {
        if(index<0 || index>total){
            throw new IndexOutOfBoundsException(index+"越界");
        }
    }

    public void update(int index, E value) {
        //更新修改元素的下标检查
        checkIndex(index);
        all[index] = value;
    }

    public void update(E old, E value) {
        int index = indexOf(old);
        if(index!=-1){
            update(index, value);
        }
    }

    public boolean contains(E e) {
        return indexOf(e) != -1;
    }

    public int indexOf(E e) {
        int index = -1;
        if(e==null){
            for (int i = 0; i < total; i++) {
                if(e == all[i]){
                    index = i;
                    break;
                }
            }
        }else{
            for (int i = 0; i < total; i++) {
                if(e.equals(all[i])){
                    index = i;
                    break;
                }
            }
        }
        return index;
    }

    public E get(int index) {
        //获取元素的下标检查
        checkIndex(index);
        return (E) all[index];
    }


    public int size() {
        return total;
    }

    public Iterator<E> iterator() {
        return new Itr();
    }

    private class Itr implements Iterator<E>{
        private int cursor;

        @Override
        public boolean hasNext() {
            return cursor!=total;
        }

        @Override
        public E next() {
            return (E) all[cursor++];
        }

        @Override
        public void remove() {
            MyArrayList.this.delete(--cursor);
        }
    }
}
测试类
package com.test.list;

import java.util.Iterator;

public class TestMyArrayList {
    public static void main(String[] args) {

        MyArrayList<String> my = new MyArrayList<>();
        my.add("hello");
        my.add("java");
        my.add("java");
        my.add("world");
        my.add(null);
        my.add(null);
        my.add("list");
        my.add("data");

        System.out.println("元素个数:" + my.size());
        for (String s : my) {
            System.out.println(s);
        }
        System.out.println("-------------------------");
        System.out.println("在[1]插入JAVA移动技术栈后:");
        my.insert(1, "JAVA移动技术栈");
        System.out.println("元素个数:" + my.size());
        for (String s : my) {
            System.out.println(s);
        }
        System.out.println("--------------------------");
        System.out.println("删除[1]位置的元素后:");
        my.delete(1);
        System.out.println("元素个数:" + my.size());
        for (String s : my) {
            System.out.println(s);
        }

       
        System.out.println("删除null元素后:");
        my.delete(null);
        System.out.println("元素个数:" + my.size());
        for (String s : my) {
            System.out.println(s);
        }
        System.out.println("------------------------------");
        System.out.println("替换[3]位置的元素为JAVA移动技术栈后:");
        my.update(3, "JAVA移动技术栈");
        System.out.println("元素个数:" + my.size());
        for (String s : my) {
            System.out.println(s);
        }

        System.out.println("替换java为JAVA后:");
        my.update("java", "JAVA");
        System.out.println("元素个数:" + my.size());
        for (String s : my) {
            System.out.println(s);
        }
        System.out.println("------------------------------------");
        System.out.println("是否包含java:" +my.contains("java"));
        System.out.println("java的位置:" + my.indexOf("java"));
        System.out.println("haha的位置:" + my.indexOf("haha"));
        System.out.println("[0]位置元素是:" + my.get(0));

        System.out.println("------------------------------------");
        System.out.println("删除字符串长度>4的元素后:");
        Iterator<String> iterator = my.iterator();
        while(iterator.hasNext()) {
            String next = iterator.next();
            if(next != null && next.length()>4) {
                iterator.remove();
            }
        }
        System.out.println("元素个数:" + my.size());
        for (String string : my) {
            System.out.println(string);
        }
    }
}

2.2 链表

链表特点
  • 数据存储在结点中,结点通过指针连接。
  • 插入和删除效率高,查询效率低。
  • Java 提供了 LinkedList 类实现链表,支持双向链表。

在这里插入图片描述

示例代码
import java.util.LinkedList;

public class LinkedListExample {
    public static void main(String[] args) {
        LinkedList<String> linkedList = new LinkedList<>();
        linkedList.add("A");
        linkedList.add("B");
        linkedList.add("C");
        System.out.println(linkedList); // 输出:[A, B, C]
    }
}

2.3 栈

栈特点

  • 先进后出(FILO)后进先出(LIFO):最后插入的元素最先被移除。
  • 栈只是逻辑结构,其物理结构可以是数组,也可以是链表,即栈结构分为顺序栈和链式栈。
  • 核心类库中的栈结构有 StackLinkedListStack 就是顺序栈,它是 Vector 的子类,而 LinkedList 是链式栈。
核心操作方法
  • peek():查看栈顶元素,不弹出。
  • pop():弹出栈顶元素。
  • push(E e):压入栈顶。
示例代码
import java.util.Stack;

public class StackExample {
    public static void main(String[] args) {
        Stack<Integer> stack = new Stack<>();
        stack.push(10);
        stack.push(20);
        stack.push(30);
        System.out.println(stack.pop()); // 输出:30
        System.out.println(stack.peek()); // 输出:20
    }
}
自定义单链表(拓展)
package com.test.list;

import java.util.Iterator;

public class MyOneWayLinkedList<E>  implements Iterable<E>{
    private Node head;
    private int total;

    public void add(E e){
        Node newNode = new Node(e, null);
        if(head == null){
            head = newNode;
        }else{
            Node node = head;
            while(node.next!=null){
                node = node.next;
            }
            node.next = newNode;
        }
        total++;
    }

    private Node[] findNodes(Object obj){
        Node[] result = new MyOneWayLinkedList.Node[2];
        Node node = head;
        Node find = null;
        Node beforeFind = null;

        if(obj == null){
            while(node != null){
                if(node.data == null){
                    find = node;
                    break;
                }
                beforeFind = node;
                node = node.next;
            }

        }else{
            while(node != null){
                if(obj.equals(node.data)){
                    find = node;
                    break;
                }
                beforeFind = node;
                node = node.next;
            }
        }
        result[0] = beforeFind;
        result[1] = find;
        return result;
    }

    public void delete(Object obj){
        Node[] nodes = findNodes(obj);
        Node beforeFind = nodes[0];
        Node find = nodes[1];
        if(find != null){
            if(beforeFind == null){
                head = find.next;
            }else {
                beforeFind.next = find.next;
            }
            total--;
        }
    }

    private Node findNode(Object obj){
        return findNodes(obj)[1];
    }

    public boolean contains(Object obj){
        return findNode(obj) != null;
    }

    public void update(E old, E value) {
        Node find = findNode(old);
        if(find != null){
            find.data = value;
        }
    }

    public int size() {
        return total;
    }

    @Override
    public Iterator<E> iterator() {
        return new Itr();
    }

    private class Itr implements Iterator<E>{
        private Node node = head;

        @Override
        public boolean hasNext() {
            return node != null;
        }

        @Override
        public E next() {
            E value = node.data;
            node = node.next;
            return value;
        }
    }


    private class Node{
        E data;
        Node next;

        Node(E data, Node next) {
            this.data = data;
            this.next = next;
        }
    }
}
测试类
package com.test.list;

public class TestMyOneWayLinkedList{
    public static void main(String[] args) {
        MyOneWayLinkedList<String> my = new MyOneWayLinkedList<>();
        my.add("hello");
        my.add("world");
        my.add(null);
        my.add(null);
        my.add("java");
        my.add("java");

        System.out.println("一共有:" + my.size());
        System.out.println("所有元素:");
        for (String s : my) {
            System.out.println(s);
        }
        System.out.println("-------------------------------------");
        System.out.println("查找java,null,haha的结果:");
        System.out.println(my.contains("java"));
        System.out.println(my.contains(null));
        System.out.println(my.contains("haha"));
        System.out.println("-------------------------------------");
        System.out.println("替换java,null后:");
        my.update("java","JAVA");
        my.update(null,"chai");
        System.out.println("所有元素:");
        for (String s : my) {
            System.out.println(s);
        }
        System.out.println("-------------------------------------");
        System.out.println("删除hello,JAVA,null后:");
        my.delete("hello");
        my.delete("JAVA");
        my.delete(null);
        System.out.println("所有元素:");
        for (String s : my) {
            System.out.println(s);
        }
    }
}

自定义双链表(拓展)

package com.test.list;

import java.util.Iterator;

public class MyLinkedList<E> implements Iterable<E>{
    private Node first;
    private Node last;
    private int total;

    public void add(E e){
        Node newNode = new Node(last, e, null);

        if(first == null){
            first = newNode;
        }else{
            last.next = newNode;
        }
        last = newNode;
        total++;
    }

    public int size(){
        return total;
    }

    public void delete(Object obj){
        Node find = findNode(obj);
        if(find != null){
            if(find.prev != null){
                find.prev.next = find.next;
            }else{
                first = find.next;
            }
            if(find.next != null){
                find.next.prev = find.prev;
            }else{
                last = find.prev;
            }

            find.prev = null;
            find.next = null;
            find.data = null;

            total--;
        }
    }

    private Node findNode(Object obj){
        Node node = first;
        Node find = null;

        if(obj == null){
            while(node != null){
                if(node.data == null){
                    find = node;
                    break;
                }
                node = node.next;
            }
        }else{
            while(node != null){
                if(obj.equals(node.data)){
                    find = node;
                    break;
                }
                node = node.next;
            }
        }
        return find;
    }

    public boolean contains(Object obj){
        return findNode(obj) != null;
    }

    public void update(E old, E value){
        Node find = findNode(old);
        if(find != null){
            find.data = value;
        }
    }

    @Override
    public Iterator<E> iterator() {
        return new Itr();
    }

    private class Itr implements Iterator<E>{
        private Node node = first;

        @Override
        public boolean hasNext() {
            return node!=null;
        }

        @Override
        public E next() {
            E value = node.data;
            node = node.next;
            return value;
        }
    }

    private class Node{
        Node prev;
        E data;
        Node next;

        Node(Node prev, E data, Node next) {
            this.prev = prev;
            this.data = data;
            this.next = next;
        }
    }
}

自定义双链表测试

package com.test.list;

public class TestMyLinkedList {
    public static void main(String[] args) {
        MyLinkedList<String> my = new MyLinkedList<>();
        my.add("hello");
        my.add("world");
        my.add(null);
        my.add(null);
        my.add("java");
        my.add("java");

        System.out.println("一共有:" + my.size());
        System.out.println("所有元素:");
        for (String s : my) {
            System.out.println(s);
        }
        System.out.println("-------------------------------------");
        System.out.println("查找java,null,haha的结果:");
        System.out.println(my.contains("java"));
        System.out.println(my.contains(null));
        System.out.println(my.contains("haha"));

        System.out.println("-------------------------------------");
        System.out.println("替换java,null后:");
        my.update("java","JAVA");
        my.update(null,"chai");
        System.out.println("所有元素:");
        for (String s : my) {
            System.out.println(s);
        }
        System.out.println("-------------------------------------");
        System.out.println("删除hello,JAVA,null后:");
        my.delete("hello");
        my.delete("JAVA");
        my.delete(null);
        System.out.println("所有元素:");
        for (String s : my) {
            System.out.println(s);
        }
    }
}

2.4 队列

队列特点

队列是逻辑结构,其物理结构可以是数组,也可以是链表。队列有普通队列、双端队列、并发队列等等,核心类库中的队列实现类有很多(后面会学到很多),LinkedList 是双端队列的实现类。

Queue 除了基本的 Collection 操作外,队列还提供其他的插入、提取和检查操作。每个方法都存在两种形式:一种抛出异常(操作失败时),另一种返回一个特殊值(nullfalse,具体取决于操作)。Queue 实现通常不允许插入 null 元素,即使在允许 null 的实现中,也不应该将 null 插入到队列中,因为 null 也用作某些方法的特殊返回值,表明队列不包含元素。

抛出异常返回特殊值
插入add(e)offer(e)
移除remove()poll()
检查element()peek()
双端队列(Deque)

Deque,名称 deque 是“double ended queue(双端队列)”的缩写,通常读为“deck”。此接口定义在双端队列两端访问元素的方法。提供插入、移除和检查元素的方法。每种方法都存在两种形式:一种形式在操作失败时抛出异常,另一种形式返回一个特殊值(nullfalse,具体取决于操作)。Deque 接口的实现类有 ArrayDequeLinkedList,它们一个底层是使用数组实现,一个使用双向链表实现。

第一个元素(头部)最后一个元素(尾部)
抛出异常特殊值抛出异常特殊值
插入addFirst(e)offerFirst(e)addLast(e)offerLast(e)
移除removeFirst()pollFirst()removeLast()pollLast()
检查getFirst()peekFirst()getLast()peekLast()

此接口扩展了 Queue 接口。在将双端队列用作队列时,将得到 FIFO(先进先出)行为。将元素添加到双端队列的末尾,从双端队列的开头移除元素。从 Queue 接口继承的方法完全等效于 Deque 方法,如下表所示:

**Queue** 方法等效 **Deque** 方法
add(e)addLast(e)
offer(e)offerLast(e)
remove()removeFirst()
poll()pollFirst()
element()getFirst()
peek()peekFirst()

双端队列也可用作 LIFO(后进先出)堆栈。应优先使用此接口而不是遗留 Stack 类。在将双端队列用作堆栈时,元素被推入双端队列的开头并从双端队列开头弹出。堆栈方法完全等效于 Deque 方法,如下表所示:

堆栈方法等效 **Deque** 方法
push(e)addFirst(e)
pop()removeFirst()
peek()peekFirst()

结论:Deque 接口的实现类既可以用作 FILO 堆栈使用,又可以用作 FIFO 队列使用。

示例代码
import java.util.LinkedList;
import java.util.Queue;

public class QueueExample {
    public static void main(String[] args) {
        Queue<String> queue = new LinkedList<>();
        queue.add("A");
        queue.add("B");
        queue.add("C");
        System.out.println(queue.poll()); // 输出:A
        System.out.println(queue.peek()); // 输出:B
    }
}

2.5 二叉树

二叉树特点
  • 每个节点最多有两个子节点。
  • Java 提供了 TreeMapTreeSet 类实现基于红黑树的有序集合。
示例代码
import java.util.TreeMap;

public class TreeMapExample {
    public static void main(String[] args) {
        TreeMap<Integer, String> treeMap = new TreeMap<>();
        treeMap.put(1, "One");
        treeMap.put(2, "Two");
        treeMap.put(3, "Three");
        System.out.println(treeMap); // 输出:{1=One, 2=Two, 3=Three}
    }
}
普通二叉树:
public class BinaryTree<E>{
    private TreeNode root; //二叉树的根结点
    private int total;//结点总个数
    
    private class TreeNode{
        //至少有以下几个部分
        TreeNode parent;
        TreeNode left;
        E data;
        TreeNode right;
        
        public TreeNode(TreeNode parent, TreeNode left, E data, TreeNode right) {
            this.parent = parent;
            this.left = left;
            this.data = data;
            this.right = right;
        }
    }
}

TreeMap红黑树:

public class TreeMap<K,V> {
    private transient Entry<K,V> root;
    private transient int size = 0;
    
    static final class Entry<K,V> implements Map.Entry<K,V> {
        K key;
        V value;
        Entry<K,V> left;
        Entry<K,V> right;
        Entry<K,V> parent;
        boolean color = BLACK;

        /**
         * Make a new cell with given key, value, and parent, and with
         * {@code null} child links, and BLACK color.
         */
        Entry(K key, V value, Entry<K,V> parent) {
            this.key = key;
            this.value = value;
            this.parent = parent;
        }
    }
}

三、总结与建议

Java 提供了对常见数据结构的完整支持,无论是基础的数组、链表,还是复杂的树、队列,都可以通过标准库轻松实现。在实际开发中,应根据场景选择合适的数据结构:

  • 快速随机访问:选择 ArrayList
  • 频繁插入和删除:选择 LinkedList
  • 先进后出:选择 Stack
  • 先进先出:选择 Queue
  • 有序存储:选择 TreeMapTreeSet

通过对这些数据结构的深入理解和灵活运用,可以显著提升程序的性能和可维护性。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

webserver的http实现

1、用了状态机&#xff0c;为什么要用状态机&#xff1f; 在逻辑处理模块中&#xff0c;响应的http请求采用主从状态机完成&#xff0c; 传统的控制流程都是按照顺序执行的&#xff0c;状态机能够处理任意顺序的事件&#xff0c;并能提供有意义的响应--即使这些事件发生的顺序和…

Uniapp Android 本地离线打包(详细流程)

一、简介 App 离线 SDK 暂时不支持 Kotlin&#xff0c;未来不清楚。 uniapp 提供了 云打包 与 本地打包 两种方案&#xff0c;云打包 需要排队且还有次数限制&#xff0c;本地打包 则就没有这些限制&#xff0c;而且会 本地打包 对开发 原生插件 有很大的帮助。 细节&#x…

记录一次电脑被入侵用来挖矿的过程(Trojan、Miner、Hack、turminoob)

文章目录 0、总结1、背景2、端倪3、有个微软的系统更新&#xff0c;就想着更新看看&#xff08;能否冲掉问题&#xff09;4、更新没成功&#xff0c;自动重启电脑5、风险文件&#xff08;好家伙命名还挺规范&#xff0c;一看名字就知道出问题了&#xff09;6、开机有一些注册表…

使用大语言模型的生物嵌入,后续应该会有很多类似文章出来!

生信碱移 语言模型嵌入 小编先前分享了使用ChatGPT基因嵌入做平替的顶刊文章GenePT&#xff0c;只需要在原本的领域工作上插入这类的GPT嵌入&#xff0c;就能够实现降维打击。 ▲ 对于GenePT或者嵌入感兴趣的铁子&#xff0c;可以点击查看上面这篇推文。 今天冲浪的时候又看…

如何在没有 iCloud 的情况下将联系人从 iPhone 传输到 iPhone

概括 近期iOS 13.5的更新以及苹果公司发布的iPhone SE在众多iOS用户中引起了不小的轰动。此外&#xff0c;不少变化&#xff0c;如暴露通知 API、Face ID 增强功能以​​及其他在 COVID-19 期间与公共卫生相关的新功能&#xff0c;吸引了 iPhone 用户尝试新 iPhone 并更新到最…

GitLab集成Runner详细版--及注意事项汇总【最佳实践】

一、背景 看到网上很多用户提出的runner问题其实实际都不是问题&#xff0c;不过是因为对runner的一些细节不清楚导致了误解。本文不系统性的介绍GitLab-Runner&#xff0c;因为这类文章写得好的特别多&#xff0c;本文只汇总一些常几的问题/注意事项。旨在让新手少弯路。 二、…

【从零开始入门unity游戏开发之——C#篇40】C#特性(Attributes)和自定义特性

文章目录 前言一、特性&#xff08;Attributes&#xff09;基本概念二、自定义特性1、自定义特性代码示例&#xff1a;2、应用自定义特性&#xff1a;3、解释3.1 **AttributeUsage 特性**3.2 特性的命名3.3 **构造函数**&#xff1a;3.4 **属性**&#xff1a; 4、使用反射获取特…

k8s基础(2)—Kubernetes-Namespace

一、Namespace概述 名字空间 在 Kubernetes 中&#xff0c;名字空间&#xff08;Namespace&#xff09; 提供一种机制&#xff0c;将同一集群中的资源划分为相互隔离的组。 同一名字空间内的资源名称要唯一&#xff0c;但跨名字空间时没有这个要求。 名字空间作用域仅针对带有…

iOS 逆向学习 - iOS Security Features:硬件与软件多重防护体系

iOS 逆向学习 - iOS Security Features&#xff1a;硬件与软件多重防护体系 iOS 安全特性全面解析&#xff1a;构筑多层次防御体系一、iOS 的硬件安全特性1. Secure Enclave&#xff08;安全隔区&#xff09;2. Hardware Root of Trust&#xff08;硬件信任根&#xff09;3. De…

计算机网络——数据链路层-流量控制和可靠传输

一、流量控制 流量控制是指由接收方及时控制发送方发送数据的速率&#xff0c;使接收方来得及接受。 • 停止等待流量控制 • 滑动窗口流量控制 1、停止—等待流量控制 停止-等待流量控制的基本原理是发送方每发出一帧后&#xff0c;就要等待接收方的应答信号&#xff…

Zookeeper是如何保证事务的顺序一致性的?

大家好&#xff0c;我是锋哥。今天分享关于【Zookeeper是如何保证事务的顺序一致性的?】面试题。希望对大家有帮助&#xff1b; Zookeeper是如何保证事务的顺序一致性的? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Zookeeper 通过多个机制来保证事务的顺序一…

实际开发中,常见pdf|word|excel等文件的预览和下载

实际开发中,常见pdf|word|excel等文件的预览和下载 背景相关类型数据之间的转换1、File转Blob2、File转ArrayBuffer3、Blob转ArrayBuffer4、Blob转File5、ArrayBuffer转Blob6、ArrayBuffer转File 根据Blob/File类型生成可预览的Base64地址基于Blob类型的各种文件的下载各种类型…

Qt使用CMake编译项目时报错:#undefined reference to `vtable for MainView‘

博主将.h文件和.cpp文件放到了不同的文件目录下面&#xff0c;如下图所示&#xff1a; 于是构建项目的时候就报错了#undefined reference to vtable for MainView&#xff0c;这个是由于src/view目录下的CMake无法自动moc头文件导致的&#xff0c;需要手动moc include/view目录…

会员制电商创新:开源 AI 智能名片与 2+1 链动模式的协同赋能

摘要&#xff1a;本文聚焦于电商领域会员制的关键作用&#xff0c;深入探讨在传统交易模式向数字化转型过程中&#xff0c;如何借助开源 AI 智能名片以及 21 链动模式商城小程序&#xff0c;实现对会员数据的精准挖掘与高效利用&#xff0c;进而提升企业的营销效能与客户洞察能…

第27周:文献阅读及机器学习

目录 摘要 Abstract 一、文献阅读 发现问题 研究方法 CNN-LSTM DT SVR 创新点 案例分析 数据准备 模型性能 预测模型的实现 仿真实验及分析 二、LSTM 1、基本结构 2、具体步骤 3、举例说明 4、原理理解 总结 摘要 本周阅读文献《Short-term water qua…

【机器遗忘之UNSIR算法】2023年IEEE Trans期刊论文:Fast yet effective machine unlearning

1 介绍 年份&#xff1a;2023 期刊&#xff1a;IEEE Transactions on Neural Networks and Learning Systems 引用量&#xff1a;170 Tarun A K, Chundawat V S, Mandal M, et al. Fast yet effective machine unlearning[J]. IEEE Transactions on Neural Networks and Le…

Linux-----进程处理(waitpid,进程树,孤儿进程)

目录 waitpid等待 进程树 孤儿进程 waitpid等待 Linux中父进程除了可以启动子进程&#xff0c;还要负责回收子进程的状态。如果子进程结束后父进程没有正常回收&#xff0c;那么子进程就会变成一个僵尸进程——即程序执行完成&#xff0c;但是进程没有完全结束&#xff0c;其…

Docker- Unable to find image “hello-world“locally

Docker- Unable to find image “hello-world“locally 文章目录 Docker- Unable to find image “hello-world“locally问题描述一. 切换镜像1. 编辑镜像源2. 切换镜像内容 二、 检查设置1、 重启dockers2、 检查配置是否生效3. Docker镜像源检查4. Dokcer执行测试 三、自定义…

Android配件应用默认启动与USB权限申请区别

使用效果&#xff1a; USB配件授权演示 选择USB配件默认打开应用 申请USB配件使用权限