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

news2025/1/8 18:37:24

「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

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

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

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

相关文章

安卓NDK视觉开发——手机拍照文档边缘检测实现方法与库封装

一、项目创建 创建NDK项目有两种方式&#xff0c;一种从新创建整个项目&#xff0c;一个在创建好的项目添加NDK接口。 1.创建NDK项目 创建 一个Native C项目&#xff1a; 选择包名、API版本与算法交互的语言&#xff1a; 选择C版本&#xff1a; 创建完之后&#xff0c;可…

MATLAB仿真:基于GS算法的经大气湍流畸变涡旋光束波前校正仿真

GS算法流程 GS&#xff08;Gerchberg-Saxton&#xff09;相位恢复算法是一种基于傅里叶变换的最速下降算法&#xff0c;可以通过输出平面和输入平面上光束的光强分布计算出光束的相位分布。图1是基于GS算法的涡旋光束畸变波前校正系统框图&#xff0c;在该框图中&#xff0c;已…

【React+TypeScript+DeepSeek】穿越时空对话机

引言 在这个数字化的时代&#xff0c;历史学习常常给人一种距离感。教科书中的历史人物似乎永远停留在文字里&#xff0c;我们无法真正理解他们的思想和智慧。如何让这些伟大的历史人物"活"起来&#xff1f;如何让历史学习变得生动有趣&#xff1f;带着这些思考&…

深入刨析数据结构之排序(上)

目录 1.内部排序 1.1概述 1.2插入排序 1.2.1其他插入排序 1.2.1.1 折半插入排序 1.2.1.2 2-路插入排序 1.3希尔排序 1.4快速排序 1.4.1起泡排序 1.4.2快速排序 1.4.2.1hoare版本 1.4.2.2挖坑版本 1.4.2.3前后指针版本 1.4.2.4优化版本 1.4.2.4.1小区间插入排序优…

AIA - APLIC之三(附APLIC处理流程图)

本文属于《 RISC-V指令集基础系列教程》之一,欢迎查看其它文章。 1 APLIC复位 APLIC复位后,其所有状态都变得有效且一致,但以下情况除外: 每个中断域的domaincfg寄存器(spec第 4.5.1 节);可能是machine-level interrupt domain的MSI地址配置寄存器(spec第4.5.3 和4.5…

openwrt 清缓存命令行

一、查看缓存 &#xff1a; free -m 二、清缓存&#xff1a;echo 3 > /proc/sys/vm/drop_caches  三、详解。 释放物理页缓存 echo 1 > /proc/sys/vm/drop_caches 释放可回收的slab对象&#xff0c;包含inode and dentry echo 2 > /proc/sys/vm/drop_caches 同时…

Linux -- 端口号、套接字、网络字节序、sockaddr 结构体

目录 什么是端口号&#xff1f; 什么是套接字&#xff1f; 网络字节序 struct sockaddr 结构体 什么是端口号&#xff1f; 我们日常上网的时候&#xff0c;主机其实是在进行两种操作&#xff1a; 1、把远端的数据拉取到本地&#xff0c;比如刷抖音的时候&#xff0c;手机向…

《数据结构》期末考试测试题【中】

《数据结构》期末考试测试题【中】 21.循环队列队空的判断条件为&#xff1f;22. 单链表的存储密度比1&#xff1f;23.单链表的那些操作的效率受链表长度的影响&#xff1f;24.顺序表中某元素的地址为&#xff1f;25.m叉树第K层的结点数为&#xff1f;26. 在双向循环链表某节点…

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

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

《Opencv》基础操作详解(4)

接上篇&#xff1a;《Opencv》基础操作详解&#xff08;3&#xff09;-CSDN博客 目录 22、图像形态学操作 &#xff08;1&#xff09;、顶帽&#xff08;原图-开运算&#xff09; 公式&#xff1a; 应用场景&#xff1a; 代码示例&#xff1a; &#xff08;2&#xff09;…

大数据高级ACP学习笔记(2)

钻取&#xff1a;变换维度的层次&#xff0c;改变粒度的大小 星型模型 雪花模型 MaxCompute DataHub

尚硅谷· vue3+ts 知识点学习整理 |14h的课程(持续更ing)

vue3 主要内容 核心&#xff1a;ref、reactive、computed、watch、生命周期 常用&#xff1a;hooks、自定义ref、路由、pinia、miit 面试&#xff1a;组件通信、响应式相关api ----> 笔记&#xff1a;ts快速梳理&#xff1b;vue3快速上手.pdf 笔记及大纲 如下&#xff…

阻抗(Impedance)、容抗(Capacitive Reactance)、感抗(Inductive Reactance)

阻抗&#xff08;Impedance&#xff09;、容抗&#xff08;Capacitive Reactance&#xff09;、感抗&#xff08;Inductive Reactance&#xff09; 都是交流电路中描述电流和电压之间关系的参数&#xff0c;但它们的含义、单位和作用不同。下面是它们的定义和区别&#xff1a; …

在 SQL 中,区分 聚合列 和 非聚合列(nonaggregated column)

文章目录 1. 什么是聚合列&#xff1f;2. 什么是非聚合列&#xff1f;3. 在 GROUP BY 查询中的非聚合列问题示例解决方案 4. 为什么 only_full_group_by 要求非聚合列出现在 GROUP BY 中&#xff1f;5. 如何判断一个列是聚合列还是非聚合列&#xff1f;6. 总结 在 SQL 中&#…

B树与B+树:数据库索引的秘密武器

想象一下&#xff0c;你正在构建一个超级大的图书馆&#xff0c;里面摆满了各种各样的书籍。B树和B树就像是两种不同的图书分类和摆放方式&#xff0c;它们都能帮助你快速找到想要的书籍&#xff0c;但各有特点。 B树就像是一个传统的图书馆摆放方式&#xff1a; 1. 书籍摆放&…

回归预测 | MATLAB实现CNN-SVM多输入单输出回归预测

回归预测 | MATLAB实现CNN-SVM多输入单输出回归预测 目录 回归预测 | MATLAB实现CNN-SVM多输入单输出回归预测预测效果基本介绍模型架构程序设计参考资料 预测效果 基本介绍 CNN-SVM多输入单输出回归预测是一种结合卷积神经网络&#xff08;CNN&#xff09;和支持向量机&#…

Linux-Ubuntu之裸机驱动最后一弹PWM控制显示亮度

Linux-Ubuntu之裸机驱动最后一弹PWM控制显示亮度 一&#xff0c; PWM实现原理二&#xff0c;软件实现三&#xff0c;正点原子裸机开发总结 一&#xff0c; PWM实现原理 PWM和学习51时候基本上一致&#xff0c;控制频率&#xff08;周期&#xff09;和占空比&#xff0c;51实验…

自定义校验注解

已有的注解不能满足所有的校验需求,特殊的情况需要自定义校验(自定义校验注解) 1.自定义注解,并在注解上指定校验逻辑 Constraint(validatedBy StateValidation.class) // 指定校验逻辑 package com.example.demo.validation;import jakarta.validation.Constraint; import j…

分数阶傅里叶变换代码 MATLAB实现

function Faf myfrft(f, a) %分数阶傅里叶变换函数 %输入参数&#xff1a; %f&#xff1a;原始信号 %a&#xff1a;阶数 %输出结果&#xff1a; %原始信号的a阶傅里叶变换N length(f);%总采样点数 shft rem((0:N-1)fix(N/2),N)1;%此项等同于fftshift(1:N)&#xff0c;起到翻…

Ubuntu 20.04安装gcc

一、安装GCC 1.更新包列表 user596785154:~$ sudo apt update2.安装gcc user596785154:~$ sudo apt install gcc3.验证安装 user596785154:~$ gcc --version二 编译C文件 1.新建workspace文件夹 user596785154:~$ mkdir workspace2.进入workspace文件夹 user596785154:~…