当前位置: 首页 > news >正文

数据结构:线性表————单链表专题

 🌈个人主页:小新_-

🎈个人座右铭:“成功者不是从不失败的人,而是从不放弃的人!”🎈

🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝

🏆所属专栏: 数据结构与算法欢迎订阅,持续更新中~~~

                      

         ✨让小新带着你快乐的学习吧~✨

目录

1. 链表的概念及结构

2、单链表的实现

准备工作

1、单链表的插入

1)头插

2)尾插

3)指定位置前插

4)指定位置后插

2、单链表的删除

1)头删

2)尾删

3)删除指定位置节点

4)删除指定位置之后节点

3、单链表的查找

4、单链表的销毁

3、链表的分类

4、 链表经典算法OJ题⽬

3.1 单链表相关经典算法OJ题1:移除链表元素(点击进入题目)

3.2 单链表相关经典算法OJ题2:反转链表(点击进入题目)

3.3 单链表相关经典算法OJ题3:合并两个有序链表(点击进入题目)

3.4 单链表相关经典算法OJ题4:链表的中间结点(点击进入题目)

3.5 循环链表经典应⽤-环形链表的约瑟夫问题(点击进入题目)

3.6 单链表相关经典算法OJ题5:分割链表(点击进入题目)


1. 链表的概念及结构

概念:链表是⼀种物理存储结构上⾮连续、⾮顺序的存储结构,数据元素的逻辑顺序是通过链表
中的指针链接次序实现的 。
链表的结构跟⽕⻋⻋厢相似,淡季时⻋次的⻋厢会相应减少,旺季时⻋次的⻋厢会额外增加⼏节。只 需要将⽕⻋⾥的某节⻋厢去掉/加上,不会影响其他⻋厢,每节⻋厢都是独⽴存在的。
⻋厢是独⽴存在的,且每节⻋厢都有⻋⻔。想象⼀下这样的场景,假设每节⻋厢的⻋⻔都是锁上的状 态,需要不同的钥匙才能解锁,每次只能携带⼀把钥匙的情况下如何从⻋头⾛到⻋尾?
最简单的做法:每节⻋厢⾥都放⼀把下⼀节⻋厢的钥匙。
在链表⾥,每节“⻋厢”是什么样的呢?
与顺序表不同的是,链表⾥的每节"⻋厢"都是独⽴申请下来的空间,我们称之为“结点/节点”
节点的组成主要有两个部分:当前节点要保存的数据和保存下⼀个节点的地址(指针变量)。
图中指针变量 plist保存的是第⼀个节点的地址,我们称plist此时“指向”第⼀个节点,如果我们希
望plist“指向”第⼆个节点时,只需要修改plist保存的内容为0x0012FFA0。
为什么还需要指针变量来保存下⼀个节点的位置?
链表中每个节点都是独⽴申请的(即需要插⼊数据时才去申请⼀块节点的空间),我们需要通过指针 变量来保存下⼀个节点位置才能从当前节点找到下⼀个节点。
结合前⾯学到的结构体知识,我们可以给出每个节点对应的结构体代码:
struct SListNode
{int data; //节点数据struct SListNode* next; //指针变量⽤保存下⼀个节点的地址
};
当我们想要保存⼀个整型数据时,实际是向操作系统申请了⼀块内存,这个内存不仅要保存整型数
据,也需要保存下⼀个节点的地址(当下⼀个节点为空时保存的地址为空)。
当我们想要从第⼀个节点⾛到最后⼀个节点时,只需要在前⼀个节点拿上下⼀个节点的地址(下⼀个 节点的钥匙)就可以了。
补充说明:
1、链式机构在逻辑上是连续的,在物理结构上不⼀定连续
2、节点⼀般是从堆上申请的
3、从堆上申请来的空间,是按照⼀定策略分配出来的,每次申请的空间可能连续,可能不连续

2、单链表的实现

准备工作

单链表实现前,有几个小段代码和问题

1、首先,我们来搞懂一个一个概念上的问题,就是节点的实参形参问题,其实就是考验对指针的理解与掌握

2、申请新的节点

代码比较简单,用malloc函数申请新节点的空间,让新节点的的data域置为x,next域为空

SLTNode* SLNewNode(SLDataType x)
{SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));newnode->Data = x;newnode->next = NULL;return newnode;
}

3、打印当前链表

上代码

void SLPrint(SLTNode* phead)
{SLTNode* pcur = phead;while (pcur){printf("%d->", pcur->Data);pcur = pcur->next;}printf("NULL");
}

4、单链表的声明

typedef int SLDataType;
typedef struct SListNode
{SLDataType Data;struct SListNode* next;
}SLTNode;

1、单链表的插入

1)头插

分析:

尾删思路比较简单,我们有头结点的指针phead,我们让我们新申请的节点的next指针,指向原来的头结点,就完成了,我们考虑一下特殊情况,如果链表为空,怎么办?那还不简单,直接成为新的节点,代码就跟不是空表一样,so easy!小小头插,拿下拿下。

void SLPushFront(SLTNode** pphead, SLDataType x)
{assert(pphead);SLTNode* newnode = SLNewNode(x);newnode->next = *pphead;*pphead = newnode;}

2)尾插

分析:

如图,我们想插入一个元素4,如何插入呢?首先,我们得找到原尾节点吧。然后让原尾节点的next指针指向4这个新节点,这样我们的4就成为了尾节点,再让4的next指针指向NULL。但有一个问题,那就是如果链表为空怎么办?那就没有尾节点了。直接将这个节点作为我们的新节点。所以,大体思路就是,先判断链表是否为空,如果是就直接作为新的节点,如果不是,我们就先找到尾节点,然后执行插入操作就可以了。

代码如下:

void SLPushBack(SLTNode** pphead, SLDataType x)
{assert(pphead);SLTNode* newnode = SLNewNode(x);//链表为空,作为结点if (*pphead == NULL){*pphead = newnode;return;}//链表不为空,寻找尾节点SLTNode* ptail = *pphead;//寻找尾节点while (ptail->next){ptail = ptail->next;}//ptail就是尾节点ptail = newnode;
}

3)指定位置前插

分析:

我们看到,要想在pos(3)之前插入,我们就要找到pos之前的节点prev,prev的next指向newnode,newnode的next指向pos。考虑特殊情况,当pos是头结点时,就没有prev,怎么办呢?我们可以直接调用头插即可。

代码如下:

void SLTInsert(SLTNode** pphead, SLTNode* pos, SLDataType x)
{assert(pphead);assert(pos);assert(*pphead);SLTNode* newnode=  SLNewNode(x);//如果pos是头结点if (pos == *pphead){SLPushFront(newnode, x);return;}SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}prev->next = newnode;newnode->next = pos;
}

4)指定位置后插

分析:

指定位置后插比指定位置前插较为简单,但要注意的是顺序,如果先把pos的next给newnode,newnode中的next保存的是pos的下一个节点地址,然后再将newnode的next指向下一节点,这样导致pos的next不再指向真正的下一节点。而应该先把pos的next赋值给newnode的next,再将pos的next指向newnode.

代码如下:

2、单链表的删除

1)头删

分析:

头删比较简单,将原来的第二个节点作为新链表的第一个节点,并将原来第一个节点释放掉,并将next赋给pphead

代码如下:

void SLPopFront(SLTNode** pphead)//头删
{assert(pphead);//链表不为空assert(*pphead);//->指向第一个节点的地址SLTNode* next = (*pphead)->next;free(*pphead);(*pphead) = next;
}

2)尾删

分析:

既然要进行删除操作,那么链表至少得有一个节点吧,所以得提前判断一下。要进行尾删,首先,我们要找到尾节点的前一个节点,我们就叫他prev吧,让prv不再指向尾节点的next域,而是NULL,然后将尾节点用free函数将尾节点的内存还给操作系统。但只有一个节点的时候呢?我们只能将该节点释放掉咯(没办法的事,无奈)

void SLPopBack(SLTNode** pphead)
{assert(pphead);//链表不为空assert(*pphead);//->指向第一个节点的地址while ((*pphead)->next==NULL)//如果只有一个节点{free(*pphead);*pphead = NULL;return;}//具有多个节点SLTNode* ptail = *pphead;SLTNode* prev = NULL;while (ptail->next){prev = ptail;ptail=ptail->next;}//找到prev了prev->next = NULL;free(ptail);
ptail=NULL//别忘了置空,以免疯狗乱咬人(狗头 狗头)
}

3)删除指定位置节点

分析:

删除指定位置的节点,我们定义一个指针prev,让prev找到pos之前的节点(寻找prev的循环条件:prev->next !=pos),此时,将prev的next指针指向pos的下一个节点,再将pos释放掉。注意,顺序不能颠倒!!!需要注意的是特殊情况,当pos就是头结点。此时没有prev,我们可以直接执行头删操作。

代码如下:

void SLErase(SLTNode** pphead, SLTNode* pos)
{assert(pphead);assert(*pphead);assert(pos);if (pos == *pphead){SLPopFront(pphead);return;}SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}(prev->next) = (pos->next);free(pos);pos = NULL;
}

4)删除指定位置之后节点

分析:

思路比较清晰,看图一目了然,将pos的next指针指向pos下一个节点的下一个节点

代码如下:

void SLEraseAfter(SLTNode* pos)
{assert(pos);assert(pos->next);pos->next = pos->next->next;free(pos->next);pos->next = NULL;
}

3、单链表的查找

没什么好说的,上代码

SLTNode* SLTFind(SLTNode** pphead, SLDataType x)
{assert(pphead);//遍历链表SLTNode* pcur = *pphead;while (pcur) //等价于pcur != NULL{if (pcur->Data == x) {return pcur;}pcur = pcur->next;}//没有找到return NULL;
}

4、单链表的销毁

上代码

void SListDesTroy(SLTNode** pphead)
{assert(pphead);assert(*pphead);SLTNode* pcur = *pphead;while (pcur){SLTNode* next = pcur->next;free(pcur);pcur = next;}*pphead = NULL;
}

完整代码如下

sqlist.c

#define _CRT_SECURE_NO_WARNINGS 1
#define _CRT_SECURE_NO_WARNINGS 1
#include"SList.h"void SLPrint(SLTNode* phead)
{SLTNode* pcur = phead;while (pcur){printf("%d->", pcur->Data);pcur = pcur->next;}printf("NULL\n");
}
SLTNode* SLNewNode(SLDataType x)
{SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));newnode->Data = x;newnode->next = NULL;return newnode;
}
void SLPushBack(SLTNode** pphead, SLDataType x)
{assert(pphead);SLTNode* newnode = SLNewNode(x);//链表为空,作为结点if (*pphead == NULL){*pphead = newnode;return;}//链表不为空,寻找尾节点SLTNode* ptail = *pphead;while (ptail->next){ptail = ptail->next;}//ptail就是尾节点ptail = newnode;
}
void SLPushFront(SLTNode** pphead, SLDataType x)
{assert(pphead);SLTNode* newnode = SLNewNode(x);newnode->next = *pphead;*pphead = newnode;
}
void SLPopBack(SLTNode** pphead)
{assert(pphead);//链表不为空assert(*pphead);//->指向第一个节点的地址while ((*pphead)->next==NULL)//如果只有一个节点{free(*pphead);*pphead = NULL;return;}//具有多个节点SLTNode* ptail = *pphead;SLTNode* prev = NULL;while (ptail->next){prev = ptail;ptail=ptail->next;}//找到prev了prev->next = NULL;free(ptail);
}
void SLPopFront(SLTNode** pphead)//头删
{assert(pphead);//链表不为空assert(*pphead);//->指向第一个节点的地址SLTNode* next = (*pphead)->next;free(*pphead);(*pphead) = next;
}//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLDataType x)
{assert(pphead);assert(pos);assert(*pphead);SLTNode* newnode=  SLNewNode(x);//如果pos是头结点if (pos == *pphead){SLPushFront(newnode, x);return;}SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}prev->next = newnode;newnode->next = pos;
}
//在指定位置之后插入数据
void SLInsertAfter(SLTNode* pos, SLDataType x)
{assert(pos);SLTNode* newnode = SLNewNode(x);newnode->next = pos->next;pos->next = newnode;
}
//删除pos节点
void SLErase(SLTNode** pphead, SLTNode* pos)
{assert(pphead);assert(*pphead);assert(pos);if (pos == *pphead){SLPopFront(pphead);return;}SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}(prev->next) = (pos->next);free(pos);pos = NULL;
}
//删除pos之后的节点
void SLEraseAfter(SLTNode* pos)
{assert(pos);assert(pos->next);pos->next = pos->next->next;free(pos->next);pos->next = NULL;
}
SLTNode* SLTFind(SLTNode** pphead, SLDataType x)
{assert(pphead);//遍历链表SLTNode* pcur = *pphead;while (pcur) //等价于pcur != NULL{if (pcur->Data == x) {return pcur;}pcur = pcur->next;}//没有找到return NULL;
}
//销毁链表
void SListDesTroy(SLTNode** pphead)
{assert(pphead);assert(*pphead);SLTNode* pcur = *pphead;while (pcur){SLTNode* next = pcur->next;free(pcur);pcur = next;}*pphead = NULL;
}

slist.h

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLDataType;
typedef struct SListNode
{SLDataType Data;struct SListNode* next;
}SLTNode;
void SLPrint(SLTNode* phead);
SLTNode* SLNewNode(SLDataType x);
void SLPushBack(SLTNode** phead, SLDataType x);
void SLPushFront(SLTNode** phead, SLDataType x);
void SLPopBack(SLTNode** pphead);
void SLPopFront(SLTNode** pphead);
SLTNode* SLFind(SLTNode** pphead, SLDataType x);//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLDataType x);
//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLDataType x);//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos);
//删除pos之后的节点
void SLTEraseAfter(SLTNode* pos);//销毁链表
void SListDesTroy(SLTNode** pphead);

测试文件这里就不包含了,读者朋友可以自己写代码的时候测试

3、链表的分类

链表的结构⾮常多样,以下情况组合起来就有8种(2 x 2 x 2)链表结构:

如下:

虽然有这么多的链表的结构,但是我们实际中最常⽤还是两种结构: 单链表 双向带头循环链表
1. ⽆头单向⾮循环链表:结构简单,⼀般不会单独⽤来存数据。实际中更多是作为其他数据结
构的⼦结构,如哈希桶、图的邻接表等等。另外这种结构在笔试⾯试中出现很多。
2. 带头双向循环链表:结构最复杂,⼀般⽤在单独存储数据。实际中使⽤的链表数据结构,都
是带头双向循环链表。另外这个结构虽然结构复杂,但是使⽤代码实现以后会发现结构会带
来很多优势,实现反⽽简单了,后⾯我们代码实现了就知道了。

4、 链表经典算法OJ题⽬

3.1 单链表相关经典算法OJ题1:移除链表元素(点击进入题目)

思路一:遍历原链表,当遇到等于vul节点的时候,就执行删除操作
但有一个问题就是,删除操作太麻烦,有没有别的更好地方法呢?
思路二:创建一个新链表,遍历原链表,当节点值不为val时,尾插到新链表尾部
typedef  struct ListNode ListNode;
struct ListNode* removeElements(struct ListNode* head, int val) {//定义新链表的头尾巴指针ListNode* newHead,*newTail;newHead=newTail=NULL;ListNode* pcur=head;while(pcur) {if(pcur->val !=val)//节点值不为val,插入链表尾部{if(newHead=NULL)//链表为空{newHead=newTail=pcur;}else//链表不为空,插入尾部{newTail->next=pcur;newTail=newTail->next;}}//等于val,直接下一个节点pcur=pcur->next;}if(newTail){newTail->next=NULL;}return newTail;
}

3.2 单链表相关经典算法OJ题2:反转链表(点击进入题目)

思路一:创建一个新链表,遍历原链表,将原链表元素依次头插在新链表当中。

思路二:定义三个指针变量,分别指向,当前节点,前驱和后继节点,改变节点指向即可。

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/typedef struct ListNode ListNode;
struct ListNode* reverseList(struct ListNode* head) {if(head==NULL){return head;}ListNode* n1,*n2,*n3;n1=NULL,n2=head,n3=head->next;ListNode* pcur;while(n2){n2->next=n1;n1=n2;n2=n3;if(n3){n3=n3->next;}}return n1;
}

3.3 单链表相关经典算法OJ题3:合并两个有序链表(点击进入题目)

思路:建立一个新链表,比较俩个链表元素,谁小就插入新链表
代码:
/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {if(list1==NULL){return list2;}if(list2==NULL){return list1;}ListNode* l1,*l2;l1=list1,l2=list2;ListNode* newHead,*newTail;newHead=newTail=(ListNode*)malloc(sizeof(ListNode));while(l1&&l2){if(l1->val<l2->val){newTail->next=l1;newTail=newTail->next;l1=l1->next;}else{newTail->next=l2;newTail=newTail->next;l2=l2->next;}}if(l1){newTail->next=l1;}if(l2){newTail->next=l2;}ListNode*ret =newHead->next;free(newHead);newHead=NULL;return ret;}

3.4 单链表相关经典算法OJ题4:链表的中间结点(点击进入题目)

思路一:遍历统计节点个数,当遍历完链表,将节点个数除以2,可以得到中间节点位置
思路二:快慢指针,定义一个快指针和一个慢指针,快指针一次走俩个元素,慢指针一次走一个元素。那当快指针遍历完链表时,慢指针就刚好指向中间节点,输出该节点即可。
/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/typedef struct ListNode ListNode;
struct ListNode* middleNode(struct ListNode* head) {ListNode* fast,*slow;fast=slow=head;while(fast&&fast->next){fast=fast->next->next;slow=slow->next;}return slow;
}

3.5 循环链表经典应⽤-环形链表的约瑟夫问题(点击进入题目)

著名的Josephus问题
据说著名犹太 历史学家 Josephus有过以下的故事:在罗⻢⼈占领乔塔帕特后,39 个犹太⼈与
Josephus及他的朋友躲到⼀个洞中,39个犹太⼈决定宁愿死也不要被⼈抓到,于是决定了⼀个⾃杀 ⽅式,41个⼈排成⼀个圆圈,由第1个⼈开始报数,每报数到第3⼈该⼈就必须⾃杀,然后再由下⼀ 个重新报数,直到所有⼈都⾃杀⾝亡为⽌。
然⽽Josephus 和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他将朋友与⾃⼰安排在
第16个与第31个位置,于是逃过了这场死亡游戏。
/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/typedef struct ListNode ListNode;
struct ListNode* partition(struct ListNode* head, int x){
if(head==NULL){return head;
}
ListNode* newHeadLess,*newTailLess,*newHeadGreagter,*newTailGreagter;newHeadLess=newTailLess=(ListNode*)malloc(sizeof(ListNode));
newHeadGreagter=newTailGreagter=(ListNode*)malloc(sizeof(ListNode));ListNode* pcur=head;
while(pcur){if(pcur->val<x){newTailLess->next=pcur;newTailLess=newTailLess->next;}else{newTailGreagter->next=pcur;newTailGreagter=newTailGreagter->next;}pcur=pcur->next;
}newTailGreagter->next=NULL;newTailLess->next=newHeadGreagter->next;ListNode*ret=newHeadLess->next;free(newHeadGreagter);free(newHeadLess);return ret;
}

3.6 单链表相关经典算法OJ题5:分割链表(点击进入题目)

思路:建立大小链表,大于x放大链表,小于x放小链表,最后连接起来

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/typedef struct ListNode ListNode;
struct ListNode* partition(struct ListNode* head, int x){
if(head==NULL){return head;
}
ListNode* newHeadLess,*newTailLess,*newHeadGreagter,*newTailGreagter;newHeadLess=newTailLess=(ListNode*)malloc(sizeof(ListNode));
newHeadGreagter=newTailGreagter=(ListNode*)malloc(sizeof(ListNode));ListNode* pcur=head;
while(pcur){if(pcur->val<x){newTailLess->next=pcur;newTailLess=newTailLess->next;}else{newTailGreagter->next=pcur;newTailGreagter=newTailGreagter->next;}pcur=pcur->next;
}newTailGreagter->next=NULL;newTailLess->next=newHeadGreagter->next;ListNode*ret=newHeadLess->next;free(newHeadGreagter);free(newHeadLess);return ret;
}

 

最后,感谢大家的观看~~

相关文章:

数据结构:线性表————单链表专题

&#x1f308;个人主页&#xff1a;小新_- &#x1f388;个人座右铭&#xff1a;“成功者不是从不失败的人&#xff0c;而是从不放弃的人&#xff01;”&#x1f388; &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd; &#x1f3c6;所属专栏&#xff1…...

多线程(54)JMM中的内存屏障

Java内存模型&#xff08;JMM&#xff09;中的内存屏障是一种保证内存可见性、顺序性的底层机制。它们是一组指令&#xff0c;用于在多线程环境中确保内存操作的有序性和可见性。内存屏障主要分为四类&#xff1a;LoadLoad、StoreStore、LoadStore和StoreLoad。 内存屏障的类型…...

什么是流量清洗?

随着网络企业的迅速发展&#xff0c;越来越多的用户都开始关注关于网络流量的问题&#xff0c;同时&#xff0c;随着网络流量的增多&#xff0c;网络上也出现了大量的垃圾信息和恶意攻击&#xff0c;给网络带来了很大的困扰&#xff0c;而流量清洗则能够解决这个问题。 流量清洗…...

淘宝API(通过商品详情接口采集商品页面数据)请求说明文档|可接入测试key

淘宝商品详情数据接口&#xff08;taobao.item_get&#xff09;是天猫开放平台提供的一种API接口&#xff0c;旨在帮助开发者获取天猫平台上的商品详情信息。通过调用这个接口&#xff0c;开发者可以获取包括商品ID、标题、价格、库存量、图片等在内的详细数据&#xff0c;从而…...

示例说明闭包函数

示例说明闭包函数 闭包函数是指在一个函数内部定义另一个函数&#xff0c;并且内部函数可以访问外部函数的局部变量&#xff0c;即使外部函数已经执行完毕。 这种功能使得闭包函数可以捕获外部函数的状态&#xff0c;提供了一种保留局部变量值的方式。闭包函数在编程中常用于…...

【自媒体创作利器】AI白日梦+ChatGPT 三分钟生成爆款短视频

AI白日梦https://brmgo.com/signup?codey5no6idev 引言 随着人工智能&#xff08;AI&#xff09;技术的快速发展&#xff0c;AI在各个领域都展现出了强大的应用潜力。其中&#xff0c;自然语言处理技术的进步使得智能对话系统得以实现&#xff0c;而ChatGPT作为其中的代表之一…...

把握零碎时间,开启长期副业兼职之旅!在家也能轻松赚钱!

转眼间&#xff0c;2024年已悄然走过三分之一。这一年&#xff0c;外界环境似乎并不那么友好&#xff0c;但对我而言&#xff0c;我的月收入仍然相对稳定。我找到的副业让我每月能赚到3000元以上&#xff0c;这让我深感庆幸。 现实中&#xff0c;只依赖主业工资的日子确实艰辛…...

HarmonyOS开发实例:【数字管家app】

样例简介 数字管家场景需要手机端、设备端和服务端三方协同完成&#xff0c;本文档介绍的demo是数字管家大场景中的手机端应用&#xff1b;用户注册登录后可创建我的家庭并管理家庭成员&#xff1b;可以添加设备&#xff08;包括智能台灯&#xff0c;智能窗帘&#xff0c;智能…...

人工智能_大模型033_LangChain003_记忆封装Memory上下文控制机制_LCEL表达式语言---人工智能工作笔记0168

## 三、记忆封装:Memory ### 3.1、对话上下文:ConversationBufferMemory from langchain.memory import ConversationBufferMemory, ConversationBufferWindowMemoryhistory = ConversationBufferMemory() history.save_context({"input": "你好啊"}…...

持安科技与顺丰正式签约!共建零信任应用安全最佳实践

近日&#xff0c;北京持安科技有限公司与顺丰科技有限公司基于零信任“应用数据网关产品”签署了合作协议&#xff0c;持安科技创始人兼CEO何艺、顺丰科技底盘领域负责人刘潭仁出席活动并签署协议。 根据协议&#xff0c;双方将基于持安科技的零信任应用数据网关产品展开合作与…...

Elasticsearch分布式搜索

实用篇-ES-环境搭建 ES是elasticsearch的简称。我在SpringBoot学习 数据层解决方案 的时候&#xff0c;写过一次ES笔记&#xff0c;可以结合一起看一下。 之前在SpringBoot里面写的相关ES笔记是基于Windows的&#xff0c;现在我们是基于docker容器来使用&#xff0c;需要你们提…...

【Unity 实用工具篇】 | UIEffect 实现一系列UGUI特效,灰度、负片、像素化特效

前言 【Unity 实用工具篇】 | UIEffect 实现一系列UGUI特效&#xff0c;灰度、负片、像素化特效一、UGUI特效插件&#xff1a;UIEffect1.1 介绍1.2 效果展示1.3 使用说明及下载 二、组件属性面板三、代码操作组件四、组件常用方法示例4.1 使用灰度特效做头像(关卡)选择 总结 前…...

ECMA进阶1之从0~1搭建react同构体系项目1

ECMA进阶 ES6项目实战前期介绍SSRpnpm 包管理工具package.json 项目搭建初始化配置引入encode-fe-lint 基础环境的配置修改package.jsonbabel相关tsconfig相关postcss相关补充scripts脚本webpack配置base.config.tsclient.config.tsserver.config.ts src环境server端&#xff1…...

【回溯】Leetcode 22. 括号生成【中等】

括号生成 数字 n 代表生成括号的对数&#xff0c;请你设计一个函数&#xff0c;用于能够生成所有可能的并且 有效的 括号组合。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;[“((()))”,“(()())”,“(())()”,“()(())”,“()()()”] 解题思路 1、使用回溯…...

Java生成带数字的图片

Java生成带数字的图片示例 在Java中&#xff0c;你可以使用java.awt和javax.imageio等图形库来生成带有数字的图片。下面是一个简单的示例代码&#xff0c;展示了如何创建并保存一张带有数字的图片。 示例代码 import javax.imageio.ImageIO; import java.awt.*; import…...

FreeSWITCH 1.10.10 简单图形化界面17 - ubuntu22.04或者debian12 安装FreeSWITCH(IamFree)

FreeSWITCH 1.10.10 简单图形化界面17 - ubuntu22.04或者debian12 安装FreeSWITCH 界面预览00、先看使用手册0、安装操作系统1、下载脚本2、开始安装3、登录网页 FreeSWITCH界面安装参考&#xff1a;https://blog.csdn.net/jia198810/article/details/132479324 界面预览 htt…...

【数据结构】06图

图 1. 定义1.1 无向图和有向图1.2 度、入度和出度1.3 图的若干定义1.4 几种特殊的图 2. 图的存储2.1 邻接矩阵-顺序存储&#xff08;数组&#xff09;2.2 邻接表-顺序存储链式存储&#xff08;数组链表&#xff09;2.3 十字链表-适用于有向图2.4 邻接多重表-适用于无向图 3. 图…...

Flink作业 taskmanager.numberOfTaskSlots 这个参数有哪几种设置方式

Flink作业 taskmanager.numberOfTaskSlots 这个参数有哪几种设置方式 taskmanager.numberOfTaskSlots 参数用于设置每个TaskManager上的任务槽&#xff08;task slot&#xff09;数量&#xff0c;决定了TaskManager可以并行执行的任务数量。这个参数可以通过多种方式进行设置。…...

京东详情比价接口优惠券(2)

京东详情API接口在电子商务中的应用与作用性体现在多个方面&#xff0c;对于电商平台、商家以及用户都带来了显著的价值。 首先&#xff0c;从应用的角度来看&#xff0c;京东详情API接口为开发者提供了一整套丰富的功能和工具&#xff0c;使他们能够轻松地与京东平台进行交互。…...

Python knn算法

KNN&#xff08;K-Nearest Neighbors&#xff09;算法&#xff0c;即K最近邻算法&#xff0c;是一种基本且广泛使用的分类和回归方法。在分类问题中&#xff0c;KNN通过查找一个样本点的K个最近邻居&#xff0c;然后根据这些邻居的类别通过多数投票或加权投票来预测该样本点的类…...

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…...

深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录

ASP.NET Core 是一个跨平台的开源框架&#xff0c;用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录&#xff0c;以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...

stm32G473的flash模式是单bank还是双bank?

今天突然有人stm32G473的flash模式是单bank还是双bank&#xff1f;由于时间太久&#xff0c;我真忘记了。搜搜发现&#xff0c;还真有人和我一样。见下面的链接&#xff1a;https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...

【Linux】C语言执行shell指令

在C语言中执行Shell指令 在C语言中&#xff0c;有几种方法可以执行Shell指令&#xff1a; 1. 使用system()函数 这是最简单的方法&#xff0c;包含在stdlib.h头文件中&#xff1a; #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

使用分级同态加密防御梯度泄漏

抽象 联邦学习 &#xff08;FL&#xff09; 支持跨分布式客户端进行协作模型训练&#xff0c;而无需共享原始数据&#xff0c;这使其成为在互联和自动驾驶汽车 &#xff08;CAV&#xff09; 等领域保护隐私的机器学习的一种很有前途的方法。然而&#xff0c;最近的研究表明&…...

定时器任务——若依源码分析

分析util包下面的工具类schedule utils&#xff1a; ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类&#xff0c;封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz&#xff0c;先构建任务的 JobD…...

鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/

使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题&#xff1a;docker pull 失败 网络不同&#xff0c;需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 在 GPU 上对图像执行 均值漂移滤波&#xff08;Mean Shift Filtering&#xff09;&#xff0c;用于图像分割或平滑处理。 该函数将输入图像中的…...

html-<abbr> 缩写或首字母缩略词

定义与作用 <abbr> 标签用于表示缩写或首字母缩略词&#xff0c;它可以帮助用户更好地理解缩写的含义&#xff0c;尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时&#xff0c;会显示一个提示框。 示例&#x…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...