【数据结构与算法】【约瑟夫问题】还在用递归?教你用链表秒杀约瑟夫

news2024/11/19 8:44:04

 🎉🎉欢迎光临🎉🎉

🏅我是苏泽,一位对技术充满热情的探索者和分享者。🚀🚀

🌟特别推荐给大家我的最新专栏《数据结构与算法:初学者入门指南》📘📘

本专栏纯属为爱发电永久免费!!!

这是苏泽的个人主页可以看到我其他的内容哦👇👇

努力的苏泽icon-default.png?t=N7T8http://suzee.blog.csdn.net/

 本文原本是对链表学习的记录笔记 因为约瑟夫问题笔记经典就拿来做大题材了,要是没学过链表或者链表还不熟悉的伙伴可以慢慢读,要是以及学过链表了,纯粹来看全新的解题思路的 可以用目录传送门往下跳

那么 开始吧

目录

引言:为什么学习链表是数据结构与算法的必备知识

单链表:定义、特点与基本操作

解释单链表的概念、结构和节点关系

单链表的抽象形态表现

示例链表抽象形态表现

单链表的基本操作

插入操作

在头部插入节点

在尾部插入节点

删除操作

删除头节点

删除尾节点

查找操作

遍历查找

递归查找

单链表的案例分析

. 双链表:定义、特点与基本操作

1.1 介绍双链表的定义和结构

1.2 学习双链表的基本操作:插入、删除、查找等

插入操作

删除操作

查找操作

【链表应用】约瑟夫问题

当然了!除了使用链表来解决约瑟夫问题,还有一种更巧妙的思路可以用数学方法直接求解。

面试官一看,眉毛邹了起来,递推可以是可以  但是这资源利用....嘶小伙子不懂得勤俭持家呀,万一栈溢出了怎么办?他正想微笑告诉你,小伙子回去等通知吧


引言:为什么学习链表是数据结构与算法的必备知识

链表是数据结构与算法中最基本、最常用的数据结构之一。它在实际应用中具有重要性和优势,不仅在面试中扮演着重要角色,而且在竞赛中也占据相当比重。

根据广泛的面试经验和回馈,链表问题是面试中常见的考点之一,并且经常出现在技术公司的编程面试中。链表问题可以考察面试者对数据结构的理解、编码能力以及解决复杂问题的能力。掌握链表的基本操作和常见问题解法,可以帮助面试者在面试过程中更好地展现自己的能力。

其次,我们来分析链表在面试题中的比重。虽然具体比例会因面试的难度和类型而有所变化,但链表问题通常占据了相当大的比重。根据统计数据,链表问题在技术公司的编程面试中占据了约20%至30%的问题比例。这意味着,如果一个面试者没有对链表问题进行足够的准备,可能会错失相当多的机会。

此外,在竞赛中,链表问题同样具有一定的比重。在算法竞赛中,链表常常被用作构建和实现其他复杂数据结构的基础,如栈、队列和图等。因此,掌握链表的知识和技巧,对于在竞赛中迅速解决问题、提高算法效率至关重要。

而本文从基础概念出发,又引入到实战面试题当中,希望能从中带给读者一些帮助 

话不多说 以下是正文 可以按照需要跳到自己需要的部分

单链表:定义、特点与基本操作

解释单链表的概念、结构和节点关系

单链表是一种由节点组成的数据结构,每个节点包含一个值和指向下一个节点的指针。这种结构使得单链表具有高效的插入和删除操作,但查找操作相对耗时。

单链表的抽象形态表现

在定义单链表的抽象形态时,我们可以通过表格框来展现其节点形态:

struct Node {
    int data;
    Node* next;
};

这里的data表示节点的数据,next表示指向下一个节点的指针。

示例链表抽象形态表现

以下是一个示例链表的抽象形态表现,我们用表格框展示链表的结构:

+---------+    +---------+    +---------+
|  data   |    |  data   |    |  data   |
+---------+    +---------+    +---------+
|  next   | -> |  next   | -> |  nullptr|
+---------+    +---------+    +---------+
   Node 1       Node 2       Node 3

单链表的基本操作

插入操作

在头部插入节点
void insertAtHead(Node*& head, int value) {
    Node* newNode = new Node(value);
    newNode->next = head;
    head = newNode;
}

插入节点后的抽象形态表现:

+---------+    +---------+    +---------+    +---------+
|  value  |    |  data   |    |  data   |    |  data   |
+---------+    +---------+    +---------+    +---------+
|  next   | -> |  next   | -> |  next   | -> |  nullptr|
+---------+    +---------+    +---------+    +---------+
  New Node     Node 1       Node 2       Node 3
在尾部插入节点
void insertAtTail(Node*& head, int value) {
    Node* newNode = new Node(value);
    if (head == nullptr) {
        head = newNode;
    } else {
        Node* temp = head;
        while (temp->next != nullptr) {
            temp = temp->next;
        }
        temp->next = newNode;
    }
}

删除操作

删除头节点
void deleteAtHead(Node*& head) {
    if (head == nullptr) {
        return;
    }
    Node* temp = head;
    head = head->next;
    delete temp;
}
删除尾节点
void deleteAtTail(Node*& head) {
    if (head == nullptr) {
        return;
    }
    if (head->next == nullptr) {
        delete head;
        head = nullptr;
        return;
    }
    Node* temp = head;
    while (temp->next->next != nullptr) {
        temp = temp->next;
    }
    delete temp->next;
    temp->next = nullptr;
}

查找操作

遍历查找
Node* search(Node* head, int value) {
    Node* temp = head;
    while (temp != nullptr) {
        if (temp->data == value) {
            return temp;
        }
        temp = temp->next;
    }
    return nullptr;
}
递归查找
Node* searchRecursive(Node* head, int value) {
    if (head == nullptr) {
        return nullptr;
    }
    if (head->data == value) {
        return head;
    }
    return searchRecursive(head->next, value);
}

单链表的案例分析

LCR 078. 合并 K 个升序链表

给定一个链表数组,每个链表都已经按升序排列。

请将所有链表合并到一个升序链表中,返回合并后的链表。

示例 1:

输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[
  1->4->5,
  1->3->4,
  2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6

示例 2:

输入:lists = []
输出:[]

示例 3:

输入:lists = [[]]
输出:[]

提示:

  • k == lists.length
  • 0 <= k <= 10^4
  • 0 <= lists[i].length <= 500
  • -10^4 <= lists[i][j] <= 10^4
  • lists[i] 按 升序 排列
  • lists[i].length 的总和不超过 10^4

题目分析: 题目要求合并K个升序链表,其中每个链表可能包含0个或多个节点。我们需要以升序顺序返回合并后的链表。

解题思路: 为了解决这个问题,我们可以使用优先队列来维护所有的头节点,并依次弹出最小的头节点,并将其对应的链表的下一个节点插入到队列中。这个过程可以看作是归并排序的一部分,因为它类似于归并排序中合并两个有序数组的操作。这种方法的时间复杂度为O(Nlogk),其中k是链表数,N是所有链表中的节点数。

代码解读:

  1. 定义一个优先队列,将所有的头节点添加到队列中。
  2. 定义一个哨兵节点,方便处理边界情况。
  3. 不断弹出最小的头节点,并将其对应的链表的下一个节点添加到队列中。
  4. 返回哨兵节点的下一个节点作为合并后的链表头。
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

// 定义一个链表节点比较函数,用于优先队列的排序
int cmp(const void* a, const void* b) {
    return (*((struct ListNode**)a))->val - (*((struct ListNode**)b))->val;
}

struct ListNode* mergeKLists(struct ListNode** lists, int listsSize){
    // 创建一个优先队列
    struct ListNode** pq = (struct ListNode**)malloc(sizeof(struct ListNode*) * listsSize);
    int size = 0;

    // 将所有的头节点添加到队列中
    for (int i = 0; i < listsSize; i++) {
        if (lists[i]) {
            pq[size++] = lists[i];
        }
    }

    // 使用自定义比较函数对队列中的元素进行排序
    qsort(pq, size, sizeof(struct ListNode*), cmp);

    // 定义一个哨兵节点,方便处理边界情况
    struct ListNode* dummy = (struct ListNode*)malloc(sizeof(struct ListNode));
    dummy->val = -1;
    dummy->next = NULL;
    struct ListNode* cur = dummy;

    // 不断弹出最小的头节点,并将其对应的链表的下一个节点插入到队列中
    while (size > 0) {
        struct ListNode* node = pq[0];
        cur->next = node;
        cur = cur->next;
        if (node->next) {
            pq[0] = node->next;
        } else {
            pq[0] = pq[--size];
        }
        if (size > 0) {
            // 对队列中的元素重新排序
            int i = 0, j = 2 * i + 1;
            while (j < size) {
                if (j + 1 < size && pq[j + 1]->val < pq[j]->val) {
                    j++;
                }
                if (pq[j]->val < pq[i]->val) {
                    struct ListNode* tmp = pq[i];
                    pq[i] = pq[j];
                    pq[j] = tmp;
                    i = j;
                    j = 2 * i + 1;
                } else {
                    break;
                }
            }
        }
    }

    return dummy->next;
}

. 双链表:定义、特点与基本操作

1.1 介绍双链表的定义和结构

在计算机科学中,双链表(Doubly Linked List)是一种常见的数据结构,它由一系列节点组成,每个节点包含两个指针,分别指向前一个节点和后一个节点,形成一个双向链表。与单链表相比,双链表可以更高效地进行向前和向后遍历,但也因为需要额外的指针而占用更多的内存空间。

下面是一个双链表节点的抽象形态表现:

节点结构
数据
前驱指针
后继指针

在这个表格框中,我们可以看到双链表节点的三个属性:数据、前驱指针和后继指针。数据存储了节点所需的信息,而前驱指针和后继指针则分别指向了前一个节点和后一个节点,使得节点之间能够互相连接。

1.2 学习双链表的基本操作:插入、删除、查找等

接下来,让我们一起学习双链表的基本操作,包括插入、删除和查找。

插入操作

在双链表中,插入操作可用于在任意位置插入一个新节点。下面是一个用 C 语言实现的双链表插入操作的示例代码:

 

#include <stdio.h>
#include <stdlib.h>

struct Node {
    int data;
    struct Node* prev;
    struct Node* next;
};

void insert(struct Node** head, int data) {
    struct Node* new_node = (struct Node*)malloc(sizeof(struct Node));
    new_node->data = data;
    new_node->prev = NULL;
    new_node->next = NULL;

    if (*head == NULL) {
        *head = new_node;
    } else {
        struct Node* current = *head;
        while (current->next != NULL) {
            current = current->next;
        }
        current->next = new_node;
        new_node->prev = current;
    }
}

在上述代码中,我们定义了一个结构体 Node,表示双链表的节点。insert 函数用于向双链表中插入一个新节点。如果双链表为空,则将新节点作为头节点;否则,遍历双链表至末尾,将新节点插入到最后一个节点之后。

删除操作

删除操作允许我们从双链表中移除指定节点。下面是一个用 C 语言实现的双链表删除操作的示例代码:

void delete(struct Node** head, int data) {
    struct Node* current = *head;
    while (current != NULL) {
        if (current->data == data) {
            if (current->prev != NULL) {
                current->prev->next = current->next;
            }
            if (current->next != NULL) {
                current->next->prev = current->prev;
            }
            if (current == *head) {
                *head = current->next;
            }
            free(current);
            return;
        }
        current = current->next;
    }
}

在上述代码中,我们定义了一个 delete 函数,用于从双链表中删除包含指定数据的节点。通过遍历双链表,我们找到目标节点后,更新前驱和后继节点的指针,并正确处理头节点的情况。最后,释放目标节点的内存。

查找操作

查找操作用于确定双链表中是否存在包含特定数据的节点。下面是一个用 C 语言实现的双链表查找操作的示例代码:

int search(struct Node* head, int data) {
    struct Node* current = head;
    while (current != NULL) {
        if (current->data == data) {
            return 1;
        }
        current = current->next;
    }
    return 0;
}

在上述代码中,我们定义了一个 search 函数,用于在双链表中搜索包含特定数据的节点。通过遍历双链表,我们可以确定是否存在满足条件的节点。

【链表应用】约瑟夫问题

上面铺垫了那么多 其实也只是为了解决问题而做的嘛  那么现在我们来面对一个实际的问题 约瑟夫问题 (典中典了属于是)

约瑟夫问题(Josephus Problem)是一个经典的数学问题,它的形式是:n个人围成一圈,从第k个人开始报数,数到m的那个人出列,然后从下一个人开始重新报数,直到最后剩下一个人。这个问题可以用链表来解决。

我们可以使用循环链表来模拟这个过程。具体地,我们先创建一个有n个节点的循环链表,每个节点代表一个人。然后,我们从第k个人开始,遍历链表并数m个人,将第m个人删除并输出,然后从下一个人开始重新报数,直到只剩下一个人为止。

下面是一个使用单向循环链表解决约瑟夫问题的示例代码:

#include <stdio.h>
#include <stdlib.h>

struct Node {
    int data;
    struct Node* next;
};

void create_circle(struct Node** head, int n) {
    struct Node* current = *head;
    for (int i = 1; i <= n; i++) {
        struct Node* new_node = (struct Node*)malloc(sizeof(struct Node));
        new_node->data = i;
        new_node->next = NULL;
        if (*head == NULL) {
            *head = new_node;
            current = new_node;
        } else {
            current->next = new_node;
            current = new_node;
        }
    }
    current->next = *head;
}

void josephus(struct Node** head, int k, int m) {
    struct Node* current = *head;
    for (int i = 1; i < k; i++) {
        current = current->next;
    }
    while (current->next != current) {
        for (int i = 1; i < m; i++) {
            current = current->next;
        }
        struct Node* temp = current->next;
        printf("%d ", temp->data);
        current->next = temp->next;
        free(temp);
    }
    printf("%d\n", current->data);
    *head = NULL;
}

int main() {
    struct Node* head = NULL;
    int n, k, m;
    scanf("%d %d %d", &n, &k, &m);
    create_circle(&head, n);
    josephus(&head, k, m);
    return 0;
}

在上述代码中,我们首先使用 create_circle 函数创建了一个有n个节点的循环链表,每个节点的数据为从1到n的整数。接着,我们使用 josephus 函数解决约瑟夫问题。该函数从第k个人开始遍历链表并数m个人,删除第m个人并输出,直到只剩下一个人为止。

运行程序时,输入n、k和m的值,即可得到最后留下的人的编号。

当然了!除了使用链表来解决约瑟夫问题,还有一种更巧妙的思路可以用数学方法直接求解。

假设n个人围成一圈,从第k个人开始报数,数到m的那个人出列。我们可以用一个递推公式来求解最后留下的人的编号。

首先,我们定义一个函数f(n, m)表示在n个人中,每次数m个人后剩下的人的编号。根据题意,我们知道当只有一个人时,即n=1时,这个人的编号为1,所以我们有基本情况:f(1, m) = 1。

接下来,我们考虑n个人的情况。当第一个人被数到并出列后,剩下的人变成了n-1个人,同时原来的第m+1个人变成了新的第一个人。因此,我们可以得到递推关系式:

f(n, m) = (f(n-1, m) + m) % n

其中,%表示取模运算。通过这个递推关系式,我们可以从n=1开始递推,直到n等于给定的人数。

下面是使用递推公式解决约瑟夫问题的示例代码:

#include <stdio.h>

int josephus(int n, int k, int m) {
    if (n == 1) {
        return 1;
    } else {
        return (josephus(n-1, k, m) + m) % n;
    }
}

int main() {
    int n, k, m;
    printf("请输入人数n:");
    scanf("%d", &n);
    printf("请输入起始位置k:");
    scanf("%d", &k);
    printf("请输入报数m:");
    scanf("%d", &m);

    int last_person = josephus(n, k, m);
    printf("最后留下的人的编号为:%d\n", last_person);

    return 0;
}

运行程序时,输入n、k和m的值,即可得到最后留下的人的编号。

通过使用递推公式,我们可以直接求解约瑟夫问题,避免了构建链表和模拟报数的过程。这种方法更加简洁、高效,并且易于理解和实现。

面试官一看,眉毛邹了起来,递推可以是可以  但是这资源利用....嘶小伙子不懂得勤俭持家呀,万一栈溢出了怎么办?他正想微笑告诉你,小伙子回去等通知吧

你说 别急 因为我还有又简单又能节约资源的办法  --环形链表来解决这个问题

于是就有了下文

使用环形链表可以很方便地解决约瑟夫问题。我们可以按照如下步骤进行:

  1. 创建一个含有n个结点的环形链表,表示围成一圈的n个人。
  2. 从第k个人开始报数,每次数到m的那个人出列,直到只剩下一个人为止。
  3. 得到最后留下的人的编号。

下面是使用C语言编写的基于环形链表的解决约瑟夫问题的示例代码:

#include <stdio.h>
#include <stdlib.h>

typedef struct node {
    int data;
    struct node *next;
} Node;

Node *createList(int n) {
    Node *head = NULL, *prev = NULL;
    for (int i = 1; i <= n; i++) {
        Node *new_node = (Node *)malloc(sizeof(Node));
        new_node->data = i;
        if (prev == NULL) {
            head = new_node;
        } else {
            prev->next = new_node;
        }
        prev = new_node;
    }
    prev->next = head;  // 链接首尾结点,形成环形链表
    return head;
}

int josephus(Node *head, int k, int m) {
    Node *prev = NULL, *curr = head;
    for (int i = 1; i < k; i++) {
        prev = curr;
        curr = curr->next;
    }
    while (curr->next != curr) {  // 只剩下一个人时退出循环
        for (int i = 1; i < m; i++) {
            prev = curr;
            curr = curr->next;
        }
        prev->next = curr->next;  // 删除当前结点
        Node *temp = curr;
        curr = curr->next;
        free(temp);
    }
    return curr->data;  // 返回最后留下的结点的编号
}

int main() {
    int n, k, m;
    printf("请输入人数n:");
    scanf("%d", &n);
    printf("请输入起始位置k:");
    scanf("%d", &k);
    printf("请输入报数m:");
    scanf("%d", &m);

    Node *head = createList(n);
    int last_person = josephus(head, k, m);
    printf("最后留下的人的编号为:%d\n", last_person);

    return 0;
}

在上述代码中,我们定义了一个名为 createList 的函数,用于创建含有n个结点的环形链表;定义了一个名为 josephus 的函数,用于解决约瑟夫问题。在 main 函数中,我们首先输入人数n、起始位置k和报数m的值,然后调用 createList 函数创建环形链表,并调用 josephus 函数求解并输出最后留下的人的编号。

通过使用环形链表来解决约瑟夫问题,我们避免了构建数组和模拟报数的过程,使得代码更加简洁、高效,并且易于理解和实现。

面试官说  还不错小伙子 第一关算你过了

当然了 未完待续.....

下篇文章我将使用腾讯和阿里的面试题讲解链表知识点 敬请关注哈 有兴趣的小伙伴可以关注我的专栏 里面全是由浅入深的讲解算法的文章 保障让每个小白也能轻易学会http://t.csdnimg.cn/wlBwt

那么下期再见了  博主去陪家人吃饭啦 新年快乐各位!

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

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

相关文章

【Kubernetes】在k8s1.24及以上版本基于containerd容器运行时测试pod从harbor拉取镜像

基于containerd容器运行时测试pod从harbor拉取镜像 1、安装高版本containerd2、安装docker3、登录harbor上传镜像4、从harbor拉取镜像 1、安装高版本containerd 集群中各个节点都要操作 yum remove containerd.io -y yum install containerd.io-1.6.22* -y cd /etc/containe…

融资项目——获取树形结构的数据

如下图所示&#xff0c;下列数据是一个树形结构数据&#xff0c;行业中包含若干子节点。表的设计如下图&#xff0c;设置了一个id为1的虚拟根节点。&#xff08;本树形结构带虚拟根节点共三层&#xff09; 实现逻辑&#xff1a; 延时展示方法&#xff0c;先展现第二层的信息&a…

动态内存经典笔试题分析

1.代码1 void GetMemory(char *p) { p (char *)malloc(100); } void Test(void) { char *str NULL; GetMemory(str); strcpy(str, "hello world"); printf(str); } int main&#xff08;&#xff09; { Test&#xff08;&#xff09;&#xff1b; return 0&#x…

RocketMQ生产常见问题

RocketMQ如何保证消息不丢失 1、哪些环节会有丢消息的可能&#xff1f; 其中&#xff0c;1&#xff0c;2&#xff0c;4三个场景都是跨网络的&#xff0c;而跨网络就肯定会有丢消息的可能。关于3这个环节&#xff0c;通常MQ存盘时都会先写入操作系统的缓存page cache中&#xf…

【MySQL】字符串函数的学习

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-J7VN4RbrBi51ozap {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…

【洛谷题解】B2056 求整数的和与均值

题目链接&#xff1a;求整数的和与均值 - 洛谷 题目难度&#xff1a;入门 涉及知识点&#xff1a;求和&#xff0c;平均值 题意&#xff1a; 输入样例&#xff1a; 4 344 222 343 222 输出样例&#xff1a; 1131 282.75000 分析&#xff1a;直接累加&#xff0c;再求平…

【知识整理】招人理念、组织结构、招聘

1、个人思考 几个方面&#xff1a; 新人&#xff1a;选、育、用、留 老人&#xff1a;如何甄别&#xff1f; 团队怎么演进&#xff1f; 有没有什么注意事项 怎么做招聘&#xff1f; 2、 他人考虑 重点&#xff1a; 1、从零开始&#xff0c;讲一个搭建团队的流程 2、标…

大数据应用对企业的价值

目录 一、大数据应用价值 1.1 大数据技术分析 1.2 原有技术场景的优化 1.2.1 数据分析优化 1.2.2 高并发数据处理 1.3 通过大数据构建新需求 1.3.1 智能推荐 1.3.2 广告系统 1.3.3 产品/流程优化 1.3.4 异常检测 1.3.5 智能管理 1.3.6 人工智能和机器学习 二、大数…

android中使用Bitmp对象绘制图形

1、引言 你是否还在因为不懂UI设计而不得不去借用别人的图片&#xff0c;甚至使用各种网图作为界面布局的一部分&#xff0c;那么今天就教你使用Bitmap对象去绘制自定义图形&#xff0c;并保存为png格式的图片&#xff0c;须知图片编辑软件本就是程序员开发出来的&#xff0c;我…

fast.ai 机器学习笔记(四)

机器学习 1&#xff1a;第 11 课 原文&#xff1a;medium.com/hiromi_suenaga/machine-learning-1-lesson-11-7564c3c18bbb 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 来自机器学习课程的个人笔记。随着我继续复习课程以“真正”理解它&#xff0c;这些笔记将继续…

Frostmourne (霜之哀伤)日志告警系统部署安装

简介 Frostmourne(霜之哀伤)是汽车之家经销商技术部监控系统的开源版本&#xff0c;用于帮助监控几乎所有数据库数据(包括Elasticsearch, Prometheus, SkyWalking, MySql 等等)。如果你已经建立起了日志系统&#xff0c; 指标体系&#xff0c;却苦恼于没有一个配套监控系统&am…

【第二十三课】最小生成树:prime 和 kruskal 算法(acwing858,859 / c++代码 )

目录 前言 Prime算法--加点法 acwing-858 代码如下 一些解释 Kruskal算法--加边法 acwing-859 并查集与克鲁斯卡尔求最小生成树 代码如下 一些解释 前言 之前学最短路的时候&#xff0c;我们都是以有向图为基础的&#xff0c;当时我们提到如果是无向图&#xf…

二、Mybatis相关概念

1.对象/关系数据库映射&#xff08;ORM) ORM全称Object/Relation Mapping&#xff1a;表示对象-关系映射的缩写ORM完成面向对象的编程语言到关系数据库的映射。当ORM框架完成映射后&#xff0c;程序员既可以利用面向对象程序设计语言的简单易用性&#xff0c;又可以利用关系数…

Swift 隐藏宝藏:“逆天改命”调整方法重载(function overloading)优先级

概览 在 Swift 语言中有很多隐藏“宝藏”悄悄深埋在不为人知的角落&#xff0c;静静等待着有缘秃头码农们的大力挖掘。 而在这里&#xff0c;我们将介绍 Swift 语言中一个非常有用的秘技&#xff1a;方法重载优先级判断以及如何改变它。 在本篇博文中&#xff0c;您将学到如下…

巴尔加瓦算法图解:算法运用(上)

目录 树反向索引傅立叶变换 并行算法MapReduce函数 树 如果能将用户名插入到数组的正确位置就好了&#xff0c;这样就无需在插入后再排序。为此&#xff0c;有人设计了一种名为二叉查找树(binary search tree)的数据结构。 每个node的children 都不大于两个。对于其中的每个…

7点原因,解密可视化大屏为啥要3D效果

真实感&#xff1a; 3D效果可以让用户感受到更真实的视觉效果&#xff0c;让用户更加身临其境&#xff0c;增强用户的参与感和沉浸感。 立体感&#xff1a; 3D效果可以给用户带来更强的立体感&#xff0c;让用户更加容易理解和感知物体的形状和大小。 美观性&#xff1a; 3D…

Android13多媒体框架概览

Android13多媒体框架概览 Android 多媒体框架 Android 多媒体框架旨在为 Java 服务提供可靠的接口。它是一个系统&#xff0c;包括多媒体应用程序、框架、OpenCore 引擎、音频/视频/输入的硬件设备&#xff0c;输出设备以及一些核心动态库&#xff0c;比如 libmedia、libmedi…

【OrangePi Zero2 智能家居】阿里云人脸识别方案

一、接入阿里云 二、C语言调用阿里云人脸识别接口 三、System V消息队列和POSIX 消息队列 一、接入阿里云 在之前树莓派的人脸识别方案采用了翔云平台的方案去1V1上传比对两张人脸比对&#xff0c;这种方案是可行&#xff0c;可 以继续采用。但为了接触更多了云平台方案&…

8种基本类型的包装类(与String的转换)

java针对8种基本数据类型&#xff0c;定义了相应的引用类型&#xff1a;包装类(封装类)&#xff0c;有了类的特点&#xff0c;就能调用类中的方法&#xff0c;java才是真正的面向对象。 基本数据类型 包装类byte Byteshort Shortint Integerlong Longfloat Floa…

Infuse通过Alist添加115网盘资源

说明 通过Alist代理管理115网盘&#xff0c;Infuse再添加Alist代理的115网盘的WebDAV 准备一台Linux服务器安装Alist 我这里用的华为云CentOS7&#xff0c;使用Docker容器 安装Alist docker run -d --restartalways -v /etc/alist:/opt/alist/data -p 5244:5244 -e PUID0 …