链表(7.27)

//头插
//让新节点指向原来的头指针(节点),即新节点位于开头
newnode->next = plist;
//再让头指针(节点)指向新节点,新节点就成为了头节点
plist = newnode;
此操作在链表为空的情况下也能正常运行。

// 单链表尾插
//第一个参数为头指针的拷贝(形参)
void SListPushBack(SLTNode* phead, SLTDataType x)
{SLTNode* tail = phead;//创建要插入的新节点SLTNode* newnode = BuySListNode(x);//遍历下一个节点指向为空的节点while (tail->next != NULL){tail = tail->next;}//将该节点与新节点链接起来tail->next = newnode;
}
phead,tail,newnode为局部变量,出了作用域就会自动销毁,而链表的节点存在于堆上,不会自动销毁。

需要让新节点充当头节点,也就是要让 plist(结构体指针)(头指针) 指向新节点,因此我们尝试将新创建的节点赋给头指针
if (phead == NULL){phead = newnode;}
但这个做法对吗,显然不对,形参是实参的一份临时拷贝,改变形参不影响实参,出了这个作用域,这两个指针就销毁了,plist也没有改变。
plist 是结构体类型的指针,要改变它的值,在函数中就需要传它的地址,也就是指针的地址。
//第一个参数为头指针的拷贝(形参)
void SListPushBack(SLTNode** pphead, SLTDataType x)
{SLTNode* newnode = BuySListNode(x);//如果链表为空//*pphead==plistif (*pphead == NULL){*pphead = newnode;}else{SLTNode* tail = *pphead;//创建要插入的新节点//遍历下一个节点指向为空的节点while (tail->next != NULL){tail = tail->next;}//将该节点与新节点链接起来tail->next = newnode;}
}
总结:
改变结构体用结构体指针;
改变结构体指针用结构体二级指针;
3.3.3头插
本篇开头已经在函数外实现过了,现在在函数中实现一次。
每一次头插都要改变 plist 头指针,因此也需要传二重指针
// 单链表的头插
void SListPushFront(SLTNode** pphead, SLTDataType x)
{SLTNode* newnode = BuySListNode(x);newnode->next = *pphead;*pphead = newnode;
}
3.3.4尾删
根据剩余节点的不同,分3种情况
1.链表为空
这是一种异常的情况,我们需要使用断言对参数加以限制,以防传空指针情况的出现。
assert(*pphead);
2.链表只剩一个节点
再删掉就为空,这时候就需要释放节点的空间,并将头指针置空,就涉及到了头指针的改变,需要引用二级指针。
if ((*pphead)->next == NULL)
{
free(*pphead);
*pphead = NULL;
}
3.链表中包含>1个节点
用 tail 找到末尾节点并将其删除,将倒数第二个节点置空,该情况下不需要二级指针。
原理图:
SLTNode* tailPre = NULL;
SLTNode* tail = *pphead;
while (tail->next != NULL)
{
tailPre = tail;
tail = tail->next;
}
free(tail);
tailPre->next = NULL;
3.3.5头删
让头指针指向第二个节点,将第一个节点释放。
// 单链表头删
void SListPopFront(SLTNode** pphead)
{assert(*pphead);//第二个节点SLTNode* newhead = (*pphead)->next;//释放第一个节点free(*pphead);//让第二个节点成为新的头节点*pphead = newhead;
}
3.3.6查找
在链表中查找值 x ,从头遍历一遍即可,遇到空节点停止。
// 单链表查找
SLTNode* SListFind(SLTNode* plist, SLTDataType x)
{SLTNode* cur = plist;while (cur){//找到了就返回地址if (cur->data == x){return cur;}cur = cur->next;}//遍历完了还没找到return NULL;
}
3.3.7 在pos之前插入X,pos为节点的指针
根据插入的位置分在第一个节点之前插入(头插)和其余的正常插入:
头插:由于我们之前写过头插,这里我们可以直接复用,需要注意参数的传递和头插函数的参数保持一致,即我们需要改变的是头指针 plist,因此传它的地址(二级指针);
正常插入:单链表的在某节点之前插入相对双链表是比较麻烦的,我们需要先通过遍历找到 pos 之前节点的指针 prev,即 prev->next==pos,然后再将代插入的节点和 prev 以及 pos 链接起来。
//在pos之前插入X,pos为节点的指针
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{//pos不能为空assert(pos);//如果为头插if (pos == *pphead){SLTPushFront(pphead, x);}else{SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}//待插入的新节点SLTNode* newnode = BuySLTNode(x);prev->next = newnode;newnode->next = pos;}
}
3.3.8 在pos之后插入X
相比在 pos 前插入就容易多了,直接将待插入的新节点和 pos 以及 pos 后面的节点 pos->next 链接起来即可,链接的时候需要注意顺序,先链接后者,再链接前者,否则 pos->next 就被新节点覆盖,找不到了。
//在pos之后插入X
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{assert(pos);SLTNode* newnode = BuySLTNode(x);//先链接新节点与pos之后的节点newnode->next = pos->next;//再链接pos与新节点pos->next = newnode;
}
3.3.9 删除pos位置的值
仅仅头删比较特别,需要将目标节点释放掉,让头指针指向下一个节点。
其余情况下先遍历找到上一个节点 prev,然后释放掉 pos 节点,让 prev 指向下一个节点。
//删除pos位置
void SLTErase(SLTNode** pphead, SLTNode* pos)
{assert(pos);//如果pos为头节点if (pos == *pphead){//直接复用,参数为二级指针SLTPopFront(pphead);}else{SLTNode* prev = *pphead;while (prev->next == pos){prev = prev->next;}prev->next = pos->next;free(pos);}
}
3.3.10 删除 pos 的下一个
这个方法不能删除头节点,也不能删除尾节点。
//删除pos的后一个
void SLTEraseAfter(SLTNode* pos)
{assert(pos);//不能删尾assert(pos->next);//将pos的下一个节点保存下来SLTNode* posNext = pos->next;//将pos和下下个节点链接起来pos->next = posNext->next;//释放pos的下一个节点free(posNext);
}
3.3.11 顺序表的销毁
依旧使用一个 cur 指针来遍历,在释放节点的时候有两种方式
创建一个 next 指针来指向下一个节点,然后释放 cur,再让 cur 指向 next
记录前一个节点 del ,cur 移动到后一个节点之后,释放 del
// 顺序表销毁
void SLTDestory(SLTNode** pphead)
{assert(pphead);SLTNode* cur = *pphead;while (cur){SLTNode* next = cur->next;free(cur);cur = next;}//销毁完毕,将头指针置空*pphead = NULL;
}
例题:
给定一个无头单链表,要求删除 pos 位置的节点,该如何实现?
常规的方法行不通,我们需要另辟蹊径
即用替换法,将 pos 下一个节点的值赋给 pos ,然后删除下一个节点,不过该方法存在一个缺陷是无法用来删除尾节点。
完整代码:
头文件
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLTDataType;
typedef struct SListNode
{SLTDataType data;struct SListNode* next;
}SLTNode;
//打印链表
void SLTPrint(SLTNode* pahead);
//开辟一个节点并赋值
SLTNode* BuySLTNode(SLTDataType X);
// 单链表尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x);
// 单链表的头插
void SLTPushFront(SLTNode** pphead, SLTDataType x);
// 单链表的尾删
void SLTPopBack(SLTNode** pphead);
// 单链表头删
void SLTPopFront(SLTNode** pphead);
//在pos之前插入X,pos为节点的指针
void SLTInsert(SLTNode** pphead, SLTNode* pos,SLTDataType x);
//在pos之后插入X
void SLTInsertAfter(SLTNode* pos, SLTDataType x);
//删除pos位置
void SLTErase(SLTNode** pphead, SLTNode* pos);
//删除pos的后一个
void SLTEraseAfter(SLTNode* pos);
// 单链表查找
SLTNode* SLTFind(SLTNode* plist, SLTDataType x);
// 顺序表销毁
void SLTDestory(SLTNode** pphead);
测试文件
#define _CRT_SECURE_NO_WARNINGS 1
#include"SList.h"
void TestSList1()
{int n = 0;printf("请输入链表的长度\n");scanf("%d", &n);printf("请依次输入每个节点的值\n");//创建头指针SLTNode* plist = NULL;for (int i = 0; i < n; i++){int val = 0;scanf("%d", &val);//开辟新节点SLTNode* newnode = BuySLTNode(val);//头插//让新节点指向原来的头指针(节点),即新节点位于开头newnode->next = plist;//再让头指针(节点)指向新节点,新节点就成为了头节点plist = newnode;}SLTPushBack(&plist, 100);SLTPrint(plist);
}
void TestSList2()
{SLTNode* plist = NULL;SLTPushBack(&plist, 1);SLTPushBack(&plist, 2);SLTPushBack(&plist, 3);SLTPushBack(&plist, 4);SLTPushBack(&plist, 5);SLTPrint(plist);SLTPushFront(&plist, 10);SLTPushFront(&plist, 20);SLTPushFront(&plist, 30);SLTPushFront(&plist, 40);SLTPrint(plist);
}
void TestSList3()
{SLTNode* plist = NULL;SLTPushBack(&plist, 1);SLTPushBack(&plist, 2);SLTPushBack(&plist, 3);SLTPushBack(&plist, 4);SLTPushBack(&plist, 5);SLTPrint(plist);SLTPopBack(&plist);SLTPrint(plist);SLTPopBack(&plist);SLTPrint(plist);SLTPopBack(&plist);SLTPrint(plist);SLTPopBack(&plist);SLTPrint(plist);SLTPopBack(&plist);SLTPrint(plist);// SLTPopBack(&plist);// SLTPrint(plist);
}
void TestSList4()
{SLTNode* plist = NULL;SLTPushBack(&plist, 1);SLTPushBack(&plist, 2);SLTPushBack(&plist, 3);SLTPushBack(&plist, 4);SLTPushBack(&plist, 5);SLTPrint(plist);SLTPopFront(&plist);SLTPrint(plist);SLTPopFront(&plist);SLTPrint(plist);SLTPopFront(&plist);SLTPrint(plist);SLTPopFront(&plist);SLTPrint(plist);SLTPopFront(&plist);//SLTPopFront(&plist);SLTPrint(plist);
}
void TestSList5()
{SLTNode* plist = NULL;SLTPushBack(&plist, 1);SLTPushBack(&plist, 2);SLTPushBack(&plist, 3);SLTPushBack(&plist, 4);SLTPushBack(&plist, 5);SLTPrint(plist);SLTNode* pos = SLTFind(plist, 3);SLTInsert(&plist, pos, 30);SLTPrint(plist);
}
void TestSList6()
{SLTNode* plist = NULL;SLTPushBack(&plist, 1);SLTPushBack(&plist, 2);SLTPushBack(&plist, 3);SLTPushBack(&plist, 4);SLTPushBack(&plist, 5);SLTPrint(plist);int x;scanf("%d", &x);SLTNode* pos = SLTFind(plist, x);if (pos){SLTInsertAfter(pos, x * 10);}SLTPrint(plist);
}void TestSList7()
{SLTNode* plist = NULL;SLTPushBack(&plist, 1);SLTPushBack(&plist, 2);SLTPushBack(&plist, 3);SLTPushBack(&plist, 4);SLTPushBack(&plist, 5);SLTPrint(plist);int x;scanf("%d", &x);SLTNode* pos = SLTFind(plist, x);if (pos){//SLTErase(&plist, pos);SLTEraseAfter(pos);pos = NULL;}SLTPrint(plist);SLTPopFront(&plist);SLTPrint(plist);SLTPopFront(&plist);SLTPrint(plist);SLTPopFront(&plist);SLTPrint(plist);SLTPopFront(&plist);SLTPrint(plist);}
int main()
{//TestSList1();//TestSList2();//TestSList3();//TestSList4();//TestSList5();//TestSList5();TestSList7();return 0;
}
实现文件
#define _CRT_SECURE_NO_WARNINGS 1
#include"SList.h"
void SLTPrint(SLTNode* phead)
{SLTNode* cur = phead;while (cur != NULL){printf("%d->", cur->data);cur = cur->next;}//结束,打印空printf("NULL\n");
}
//开辟节点并赋值
SLTNode* BuySLTNode(SLTDataType X)
{SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));if (newnode == NULL){perror("malloc");exit(-1);}newnode->data = X;newnode->next = NULL;return newnode;
}
// 单链表尾插
//第一个参数为头指针的拷贝(形参)
void SLTPushBack(SLTNode** pphead, SLTDataType x)
{SLTNode* newnode = BuySLTNode(x);//如果链表为空//*pphead==plistif (*pphead == NULL){//改变结构体指针,用结构体二级指针*pphead = newnode;}else{SLTNode* tail = *pphead;//创建要插入的新节点//遍历下一个节点指向为空的节点while (tail->next != NULL){tail = tail->next;}//改变结构体用结构体指针,将该节点与新节点链接起来tail->next = newnode;}
}
// 单链表的头插
void SLTPushFront(SLTNode** pphead, SLTDataType x)
{SLTNode* newnode = BuySLTNode(x);newnode->next = *pphead;*pphead = newnode;
}
// 单链表的尾删
void SLTPopBack(SLTNode** pphead)
{//限制参数不为空assert(*pphead);//仅有一个节点的情况if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;}//有两个及以上节点的情况else{//尾节点的前一个节点SLTNode* tailPre = NULL;SLTNode* tail = *pphead;while (tail->next != NULL){tailPre = tail;//tail往后走之前赋给前一个指针tail = tail->next;}free(tail);tailPre->next = NULL;}
}
// 单链表头删
void SLTPopFront(SLTNode** pphead)
{assert(*pphead);//第二个节点SLTNode* newhead = (*pphead)->next;//释放第一个节点free(*pphead);//让第二个节点成为新的头节点*pphead = newhead;
}
// 单链表查找
SLTNode* SLTFind(SLTNode* plist, SLTDataType x)
{SLTNode* cur = plist;while (cur){//找到了就返回地址if (cur->data == x){return cur;}cur = cur->next;}//遍历完了还没找到return NULL;
}
//在pos之前插入X,pos为节点的指针
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{//pos不能为空assert(pos);//如果为头插if (pos == *pphead){SLTPushFront(pphead, x);}else{SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}//待插入的新节点SLTNode* newnode = BuySLTNode(x);prev->next = newnode;newnode->next = pos;}
}
//在pos之后插入X
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{assert(pos);SLTNode* newnode = BuySLTNode(x);//先链接新节点与pos之后的节点newnode->next = pos->next;//再链接pos与新节点pos->next = newnode;
}
//删除pos位置
void SLTErase(SLTNode** pphead, SLTNode* pos)
{assert(pos);//如果pos为头节点if (pos == *pphead){//直接复用,参数为二级指针SLTPopFront(pphead);}else{SLTNode* prev = *pphead;while (prev->next == pos){prev = prev->next;}prev->next = pos->next;free(pos);}
}
//删除pos的后一个
void SLTEraseAfter(SLTNode* pos)
{assert(pos);//不能删尾assert(pos->next);//将pos的下一个节点保存下来SLTNode* posNext = pos->next;//将pos和下下个节点链接起来pos->next = posNext->next;//释放pos的下一个节点free(posNext);
}
// 顺序表销毁
void SLTDestory(SLTNode** pphead)
{assert(pphead);SLTNode* cur = *pphead;while (cur){SLTNode* next = cur->next;free(cur);cur = next;}//销毁完毕,将头指针置空*pphead = NULL;
}
相关文章:

链表(7.27)
3.3 链表的实现 3.3.1头插 原理图: newnode为新创建的节点 实现: //头插 //让新节点指向原来的头指针(节点),即新节点位于开头 newnode->next plist; //再让头指针(节点)指向新节点&#…...

在 Elasticsearch 中实现自动完成功能 1:Prefix queries
自动完成与搜索功能不同 - 我们应该在用户键入下一个字符后立即更新自动完成选项,每秒都会访问数据库,过滤数百万条记录,而不会导致任何性能下降! Elasticsearch 是一种可以轻松实现此类功能的技术,它是一种基于 Apac…...

『PyQt5-Qt Designer篇』| 13 Qt Designer中如何给工具添加菜单和工具栏?
13 Qt Designer中如何给工具添加菜单和工具栏? 1 创建默认窗口2 添加菜单栏3 查看和调用1 创建默认窗口 当新创建一个窗口的时候,默认会显示有:菜单栏和状态栏,如下: 可以在菜单栏上右键-移除菜单栏: 可以在菜单栏上右键-移除状态栏: 2 添加菜单栏 在窗口上,右键-创建…...

Android Studio新建项目教程
Android Studio新建项目教程 一、创建新项目 二、选择空白页项目类型 配置然后finish 等待项目完成初试化 等待初始化结束,创建完成...

前端页面布局之【响应式布局】
目录 🌟前言🌟优点🌟缺点🌟media兼容性🌟利用CSS3-Media Query实现响应式布局🌟常见的媒体类型🌟常见的操作符🌟属性值🌟设备检测🌟响应式阈值选取dz…...
定制排序小案例
案例:自定义 Book 类,里面包含 name 和 price,按 price 排序(从大到小)。 要求使用两种方式排序 , 有一个 Book[] books 4 本书对象. 使用前面学习过的传递 实现 Comparator 接口匿名内部类,也称为定制排序。 可以按照 price …...

如何设计一个ToC的弹窗
本文主要分享了如何设计一个具有高可扩展性的弹窗功能。 本设计参考了优惠券功能的设计思路,有兴趣的朋友可以看看优惠券的分享:如何设计一个可扩展的优惠券功能_java优惠券系统设计-CSDN博客 一、需求介绍 假如你的项目需要实现以下弹窗,…...

Idea执行Pom.xml导入jar包提示sun.misc.BASE64Encoder jar找不到---SpringCloud工作笔记197
奇怪之前都是好好的,这个是因为,jdk的版本不对,重新打开以后自动被选择成jdk11了...记录一下 原因是从jdk9的时候,这个jar包已经被删除了,所以会报错,如果你用的是jdk自带的这个jar包就会报错,那么还可以,修改,不让他用jdk的,让他用 用org.apache.commons.codec.binary.Base64…...
大数据面试题:Spark和Flink的区别
面试题来源: 《大数据面试题 V4.0》 大数据面试题V3.0,523道题,679页,46w字 可回答:1)Spark Streaming和Flink的区别 问过的一些公司:杰创智能科技(2022.11),阿里蚂蚁(2022.11)&…...
2023年9月青少年软件编程(C 语言) 等级考试试卷(二级)
2023年9月青少年软件编程(C 语言) 等级考试试卷(二级) 编程题 1.数组指定部分逆序重放 题目描述 将一个数组中的前k项按逆序重新存放。 例如,将数组8,6,5,4,1前3项逆序重放得到5,6,8,4,1。 输入 输入为两行ÿ…...

【Wifi】Wifi架构介绍
Wifi架构介绍 本文基于Android介绍其Wifi架构。Wifi是许多操作系统提供的重要功能之一,特别是越来越多的车载系统wifi是其必备功能。为啥wifi是必备功能? 一方面是传统的上网(现在有些车载使用DCM模块管理网络),另一方…...

攻防世界数据逆向 2023
https://adworld.xctf.org.cn/contest/list?rwNmOdr1697354606875 目录 请求数据参数加密 cookie加密 响应数据解密 代码 请求数据参数加密 我们可以根据请求的关键字qmze1yzvhyzcyyjr获取到对应的加密地方 可以看到使用了函数_0x1dc70进行了加密 cookie加密 该步骤需…...

分布式链路追踪如何跨线程
背景 我们希望实现全链路信息,但是代码中一般都会异步的线程处理。 解决思路 我们可以对以前的 Runable 和 Callable 进行增强。 可以使用 ali 已经存在的实现方式。 TransmittableThreadLocal (TTL) 解决异步执行时上下文传递的问题 核心的实现思路如下&#…...

怎样在线修剪音频文件了?【免费,无须注册】
怎样在线修剪音频文件了? 推荐一个免费网址,且不用任何注册,直接可以使用 https://mp3cut.net/cn/ 上传音频文件, 拖动前后滚动条,对音频文件进行修剪。 修剪完成,可以保存如下格式 enjoy!! 作者简介…...

iMeta框架使用方法
📢📢📢📣📣📣 哈喽!大家好,我是「奇点」,江湖人称 singularity。刚工作几年,想和大家一同进步🤝🤝 一位上进心十足的【Java ToB端大厂…...

视频编辑软件 Premiere Pro 2024 macv24.0中文版 (pr2024)
Premiere Pro 2024 mac编辑任何现代格式的素材,从8K到虚拟现实。广泛的原生文件支持和简单的代理工作流程可以轻松使用您的媒体,即使在移动工作站上也是如此。提供针对任何屏幕或平台优化的内容比以往任何时候都快。 Premiere Pro 2024 Mac版软件介绍 视…...
C/C++:双向队列的实现
/** * * Althor:Hacker Hao * Create:2023.10.11 * */#include <bits/stdc.h> using namespace std; #define MAXSIZE 200 typedef struct Deque {int front; //头int rear; //尾int num; //队列中的元素数量int arr[MAXSIZE]; //队列中存储的数字 };Deque…...

MySQL逻辑架构
文章目录 逻辑架构剖析1. 连接层2. 服务层3. 引擎层4. 存储层 SQL执行流程1. MySQL中的 SQL执行流程(理论)2. MySQL8中的 SQL 执行流程(实践)确认profiling 是否开启多次执行相同SQL查询查看profiles查看profile 3. SQL语法顺序 数…...

python爬虫练手项目之获取某地企业名录
因为很多网站都增加了登录验证,所以需要添加一段利用cookies跳过登陆验证码的操作 import pandas as pd import requests from lxml import etree # 通过Chrome浏览器F12来获取cookies,agent,headers cookies {ssxmod_itna2:eqfx0DgQGQ0QGDC…...
Python —— 接口自动化(1)
1、接口测试的基础概述 1、接口测试的方式 1、主流的工具类型 - jmeter,postman,apifox,fastapi,apipost.... 2、公开的自动化平台 - metersphere,yapi.... 3、公司内部自研平台 - 4、全面使用代码自己去完成框架搭建,项目实战.... 不论是平台还是工具࿰…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
React 第五十五节 Router 中 useAsyncError的使用详解
前言 useAsyncError 是 React Router v6.4 引入的一个钩子,用于处理异步操作(如数据加载)中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误:捕获在 loader 或 action 中发生的异步错误替…...

springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例
文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...

FFmpeg:Windows系统小白安装及其使用
一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】,注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录(即exe所在文件夹)加入系统变量…...