学习笔记---看完就会的单链表的应用~~


目录

1.单链表经典算法🫵

1.1 单链表相关经典算法OJ题1:移除链表元素

1.2 单链表相关经典算法OJ题2:反转链表

1.3 单链表相关经典算法OJ题3:合并两个有序链表

1.4 单链表相关经典算法OJ题4:链表的中间结点

1.5 循环链表经典应⽤-环形链表的约瑟夫问题

1.6 单链表相关经典算法OJ题5:分割链表

2. 基于单链表再实现通讯录项⽬👑

2.0 Slist.h(底层逻辑)

2.1 SList.c(底层逻辑)

2.2 Contact.h

2.3 Contact.c

2.4 test.c

2.5 最终效果呈现


1.单链表经典算法🫵

1.1 单链表相关经典算法OJ题1:移除链表元素

 力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台


方法1:直接在原链表上面执行删除操作

方法2:创建一个新链表,将不等于val的数据存入

我们这里使用方法2,也更推荐方法2,因为更简单



1.2 单链表相关经典算法OJ题2:反转链表

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台


方法1:创建一个新链表,遍历原链表,将原链表的节点依次头插到新链表

方法2:在原链表的基础上,翻转箭头方向

我们这里更推荐方法2,因为更简单




1.3 单链表相关经典算法OJ题3:合并两个有序链表

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台


解法1:遍历原链表,将小的放到大的之前,会涉及到在指定位置之前插入数据

解法2:创建1个新链表,遍历2个原链表,比较之后放入新链表

我们这里更推荐方法2,因为更简单


typedef struct ListNode ListNode;
 struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
     //判断链表是否为空
if(list1==NULL){
   return list2; 
}
if(list2==NULL){
   return list1;
}
//创建指针遍历原链表
ListNode* cur1=list1;
ListNode* cur2=list2;
 //创建新链表---带头---不考虑是否为空
 ListNode* newhead,*newtail;
 newhead=newtail=(ListNode*)malloc(sizeof(ListNode));
 //判断空间是否开辟成功
 if(newhead==NULL||newtail==NULL)
 {
     perror("malloc");
     exit(1);
 }
while(cur1&&cur2)
{
    if(cur1->val<cur2->val)
    {
        newtail->next=cur1;
        newtail=newtail->next;
        cur1=cur1->next;
    }
    else
    {
        newtail->next=cur2;
        newtail=newtail->next;
        cur2=cur2->next;
    }
}
//也可能list1和list2的个数不相同
if(cur1)
{
    newtail->next=cur1;
}
if(cur2)
{
    newtail->next=cur2;
}
//free
ListNode* rethead=newhead->next;
free(newhead);
return rethead;
}

1.4 单链表相关经典算法OJ题4:链表的中间结点

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台




注意while的判断条件不能交换位置,&&会先判断前面的,如果前面为假,则不进去while循环

如果5个数据,fast->next放在前面,我们fast走到第四个数据的时候,fast->next已经指向NULL了,循环结束了


1.5 循环链表经典应⽤-环形链表的约瑟夫问题

环形链表的约瑟夫问题_牛客题霸_牛客网

著名的Josephus问题

据说著名犹太 历史学家 Josephus有过以下的故事:在罗⻢⼈占领乔塔帕特后,39 个犹太⼈与Josephus及他的朋友躲到⼀个洞中,39个犹太⼈决定宁愿死也不要被⼈抓到,于是决定了⼀个⾃杀⽅式,41个⼈排成⼀个圆圈,由第1个⼈开始报数,每报数到第3⼈该⼈就必须⾃杀,然后再由下⼀个重新报数,直到所有⼈都⾃杀⾝亡为⽌。

然⽽Josephus 和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他将朋友与⾃⼰安排在第16个与第31个位置,于是逃过了这场死亡游戏。



/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 *
 * 
 * @param n int整型 
 * @param m int整型 
 * @return int整型
 */
 //创建带环链表
 #include <stdio.h>
#include <stdlib.h>
typedef struct ListNode ListNode;
//申请空间
ListNode* ListByNode(int x)
{
    ListNode* node=(ListNode*)malloc(sizeof(ListNode));
    if(node==NULL)
    {
        perror("malloc fail!");
        exit(1);
    }
    node->val=x;
    node->next=NULL;
    return node;
}
ListNode* CreateList(int n)
{
    //创建单链表
    ListNode* phead=ListByNode(1);
    ListNode* pTail=phead;
    for(int i=2;i<=n;i++)
    {
        ListNode* node=ListByNode(i);
        pTail->next=node;
        pTail=pTail->next;
    }
    //创建带环链表
    pTail->next=phead;
    return pTail;//有尾节点就能找到头节点
}
int ysf(int n, int m ) {
    ListNode* prev=CreateList(n);//prev指代尾节点
    //进行游戏
    ListNode* cur=prev->next;
    int count=1;//cur指向头节点,报数1
    while(cur->next!=cur)//cur->next=cur时,只剩1个人了
    {
        if(count==m)
        {
            prev->next=cur->next;
            free(cur);
            cur=prev->next;
            count=1;//重新开始报数
        }
        else
        {
            prev=cur;
            cur=cur->next;
            count++;
        }
    }
    return cur->val;
}

1.6 单链表相关经典算法OJ题5:分割链表

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台


思路:创建2个带头(不用考虑链表是否为空)的新链表,遍历原链表,将小于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;
//创建2个带头的新链表
ListNode* lesshead,* lesstail;
ListNode* biggerhead,* biggertail;
//申请空间
lesshead=lesstail=(ListNode*)malloc(sizeof(ListNode));
biggerhead=biggertail=(ListNode*)malloc(sizeof(ListNode));
//创建指针遍历原链表
ListNode* cur=head;
while(cur)
{
    if(cur->val<x)
    {
        lesstail->next=cur;
        lesstail=lesstail->next;
    }
    else
    {
        biggertail->next=cur;
        biggertail=biggertail->next;
    }
    cur=cur->next;
}
//如果没有把大链表的尾节点置为NULL,那么会造成超出时间限制的问题
if(biggertail)
{
    biggertail->next=NULL;
}
//把小链表和大链表的尾节点和第一个节点相连
lesstail->next=biggerhead->next;
//free
free(biggerhead);
//大链表的哨兵位没有用到直接free就可以,但是小链表的哨兵位用到了,不能直接free--->先存储起来,然后free
ListNode* rethead=lesshead->next;
free(lesshead);
return rethead;
}

2. 基于单链表再实现通讯录项⽬👑

有了上次的顺序表实现通讯录📇,我们这次基于单链表再实现通讯录项⽬就显得比较简单了,由于思路和要实现的目标都差不多,这里我就不再赘述了,需要的请自行看之前的博客,博客链接:学习笔记---不容错过的顺序表的应⽤~~-CSDN博客文章浏览阅读148次,点赞36次,收藏22次。顺序表实现通讯录📇,经典算法OJ题https://blog.csdn.net/2301_79184587/article/details/133929298

学习笔记---0基础+干货满满的单链表专题~~-CSDN博客文章浏览阅读175次,点赞38次,收藏24次。超基础的单链表的知识!!!https://blog.csdn.net/2301_79184587/article/details/133965720

2.0 Slist.h(底层逻辑)

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
#include<string.h>
#define _CRT_SECURE_NO_WARNINGS 1
#include"Contact.h"//包含头文件

//定义单链表节点的结构体(创建)
//typedef int SLDataType;

//替换
typedef struct PersonInfo SLDataType;
typedef struct SListNode
{
	SLDataType data;
	struct SListNode* next;
}SLNode;

//尾插
void SLPushBack(SLNode** pphead, SLDataType x);//一级指针要二级指针接受才可以改变形参

//头插
void SLPushFront(SLNode** pphead, SLDataType x);//一级指针要二级指针接受才可以改变形参

//尾删
void SLPopBack(SLNode** pphead);

//头删
void SLPopFront(SLNode** pphead);

//打印---展示
void SLPrint(SLNode* phead);

//查找数据
SLNode* SLFind(SLNode** pphead, SLDataType x);

//指定位置之前插入
void SLInsert(SLNode** pphead, SLNode* pos, SLDataType x);

//指定位置之后插入
void SLInsertAfter(SLNode* pos, SLDataType x);

//删除pos节点
void SLErase(SLNode** pphead, SLNode* pos);

//删除pos节点之后的节点
void SLEraseAfter(SLNode* pos);

//销毁
void SLDesTroy(SLNode** pphead);

2.1 SList.c(底层逻辑)

#include"SList.h"
//打印
void SLPrint(SLNode* phead)
{
	//循环打印
	SLNode* pcur = phead;//pcur从头节点开始遍历链表
	//不用phead遍历--->以后需要用到指向头节点的地址时,帮助我找到地址
	while (pcur)//pcur指向NULL的时候结束遍历
	{
		printf("%d->", pcur->data);
		pcur = pcur->next;//pcur指向下一个节点继续遍历
	}
	printf("NULL\n");
}

//插入数据都需要创建空间--->我们单独写出来,避免重复多次
SLNode* SLByNNode(SLDataType x)
{
	SLNode* node = (SLNode*)malloc(sizeof(SLNode));
	if (node == NULL)
	{
		perror("malloc");
		return 1;
	}
	node->data = x;
	node->next = NULL;
	return node;
}
//尾插
void SLPushBack(SLNode** pphead, SLDataType x)//一级指针要二级指针接受才可以改变
{   //传过来的指针不能为空
	assert(pphead);
	SLNode* node = SLByNNode(x);
	
	//链表为空,直接插入
	if (*pphead == NULL)
	{
		*pphead = node;
		return 1;
	}
	//到这说明不为空,遍历
	SLNode* pcur = *pphead;
	while (pcur->next)
	{
		pcur = pcur->next;
	}
	pcur->next = node;
}
//头插
void SLPushFront(SLNode** pphead, SLDataType x)//一级指针要二级指针接受才可以改变形参
{
	//传过来的指针不能为空
	assert(pphead);
	SLNode* node = SLByNNode(x);
	//新节点和原来的头节点链接
	node->next = *pphead;
	//新节点成为新的头节点
	*pphead = node;
}

//尾删
void SLPopBack(SLNode** pphead)
{
	assert(pphead);
	assert(*pphead);
	//只有1个节点
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	//多个节点
	else
	{
		SLNode* prev = NULL;
		SLNode* ptail = *pphead;
		while (ptail->next!=NULL)
		{
			prev = ptail;
			ptail = ptail->next;
		}
		prev->next = ptail->next;
		free(ptail);
		ptail = NULL;
	}
}

//头删
void SLPopFront(SLNode** pphead)
{
	assert(pphead&&*pphead);
	SLNode* del = *pphead;
	*pphead = (*pphead)->next;
	free(del);
	del = NULL;
}

//查找数据
//SlNode* SLFind(SlNode** pphead, SLDataType x)
//{
//	assert(pphead);
//	SlNode* pcur = *pphead;
//	while (pcur)
//	{
//		if (pcur->data == x)
//		{
//			return pcur;
//		}
//		pcur = pcur->next;
//	}
//	return NULL;
//}

//指定位置之前插入
void SLInsert(SLNode** pphead, SLNode* pos, SLDataType x)
{
	assert(pphead && *pphead&&pos);
	//创建空间
	SLNode* node = SLByNNode(x);
	//pos为第一个节点(只有1个节点)
	if (pos == (*pphead))
	{
		node->next = *pphead;
		*pphead = node;
		return 1;
	}
	//pos不为第一个节点
	//找pos节点的前一个节点
	SLNode* prev = *pphead;
	while (prev->next != pos)
	{
		prev = prev->next;
	}
	node->next = pos;
	prev->next = node;
}

//指定位置之后插入
void SLInsertAfter(SLNode* pos, SLDataType x)
{
	assert(pos);
	//创建空间
	SLNode* node = SLByNNode(x);
	node->next = pos->next;
	pos->next = node;
}

//删除pos节点
void SLErase(SLNode** pphead, SLNode* pos)
{
	assert(pphead && *pphead && pos);
	//pos是第一个节点
	if (pos==(*pphead))
	{
		*pphead= (*pphead)->next;
		free(pos);
		return 1;
	}
	//pos不是第一个节点
	SLNode* prev = *pphead;
	while (prev->next != pos)
	{
		prev = prev->next;
	}
	prev->next = pos->next;
	free(pos);
	pos = NULL;//出于规范
}

//删除pos节点之后的节点
void SLEraseAfter(SLNode* pos)
{
	//尾节点不行,空指针也不行
	assert(pos&&pos->next);
	SLNode* del = pos->next;
	pos->next = del->next;
	free(del);
}

//销毁
void SLDesTroy(SLNode** pphead)
{
	assert(pphead);
	SLNode* pcur = *pphead;
	while (pcur)
		//注意:如果是pcur->next,那么循环将结束于尾节点没有free的时候
	{
		SLNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	*pphead = NULL;
}

2.2 Contact.h

#pragma once
#define NAME_MAX 100
#define SEX_MAX 4
#define TEL_MAX 11
#define ADDR_MAX 100


//前置声明---通讯录的底层逻辑是由单链表来实现的
typedef struct SListNode contact;

//用户数据
typedef struct PersonInfo
{
    char name[NAME_MAX];
    char sex[SEX_MAX];
    int age;
    char tel[TEL_MAX];
    char addr[ADDR_MAX];
}PeoInfo;

//初始化通讯录
void InitContact(contact** con);
//添加通讯录数据
void AddContact(contact** con);
//删除通讯录数据
void DelContact(contact** con);
//展示通讯录数据
void ShowContact(contact* con);
//查找通讯录数据
void FindContact(contact* con);
//修改通讯录数据
void ModifyContact(contact** con);
//销毁通讯录数据
void DestroyContact(contact** con);

2.3 Contact.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"Contact.h"
#include"SList.h"
//初始化通讯录

//创建+导入通讯录
void LoadContact(contact** con)
{
	FILE* pf = fopen("contact.txt", "rb");//需要contact.txt先存在,才能打开成功,否则出错
	if (pf == NULL)
		perror("fopen error!\n");
	return 1;

	//循环读取数据
	PeoInfo info;
	while (fread(&info, sizeof(info), 1, pf))
	{
		SLPushBack(con, info);
	}
}

void InitContact(contact** con)
{
	LoadContact(con);
}

//添加通讯录数据
void AddContact(contact** con)
{
	//接下来要获取的数据都是PeoInfo结构体里我们设置的数据
	PeoInfo info;
	printf("请输入要添加的联系人的姓名:");
	scanf("%s", &info.name);//name是数组名--->本来就是地址
	printf("请输入请输入要添加的联系人的性别:");
	scanf("%s", &info.sex);
	printf("请输入要添加的联系人的年龄:");
	scanf("%d", &info.age);//age是int类型的数据--->取地址
	printf("请输入要添加的联系人的号码:");
	scanf("%s", &info.tel);
	printf("请输入要添加的联系人的地址:");
	scanf("%s", &info.addr);
	//数据获取到之后存储到info中
	//接下来,我们需要在单链表中插入数据
	SLPushBack(con, info);//直接调用单链表的尾插
}

//删除通讯录数据
//删除联系人
//由于删除/修改/查找联系人都需要判断联系人是否存在,所以我们把判断联系人是否存在单独写出来
contact* FindByName(contact* con, char name[])
{
	contact* cur = con;
	while (cur)
	{
		if (strcmp(cur->data.name, name) == 0)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}
void DelContact(contact** con)
{
	//我们需要使用联系人众多信息中的一项来查找联系人是否存在
	//这里直接要求输入联系人的姓名进行查找
	printf("请输入要删除的联系人的姓名:");
	//创建一个name数组存储要输入的姓名
	char name[NAME_MAX];
	scanf("%s", name);
	//调用函数判断联系人是否存在
    //1.存在--->根据返回的下标删除--->即为调用顺序表的删除指定位置的数据
    //2.不存在--->说明要删除的联系人不存在
	contact* pos=FindByName(*con, name);
	//判断是否存在
	if (pos == NULL)
	{
		printf("要删除的联系人不存在!\n");
		return 1;
	}
		SLErase(con, pos);
		printf("删除成功!\n");
}

//展示通讯录数据
void ShowContact(contact* con)
{
	//打印通讯录存储的所有数据
	//为了更加好看--->我们先输出表头
	printf("%-10s %-4s %-4s %15s %-10s\n", "姓名", "性别", "年龄", "联系电话", "地址");
	contact* cur = con;
	while(cur)
	{
		printf("%-10s %-4s %-4d %15s %-10s\n",//表头对齐--->美观
			cur->data.name,
			cur->data.sex,
			cur->data.age,
			cur->data.tel,
			cur->data.addr
		);
		cur = cur->next;
	}
}

//查找通讯录数据
void FindContact(contact* con)
{
	//我们需要使用联系人众多信息中的一项来查找联系人是否存在
    //这里直接要求输入联系人的姓名进行查找
    //创建一个name数组存储要输入的姓名
	char name[NAME_MAX];
	printf("请输入要查找的联系人的姓名:");
	scanf("%s", name);
	//调用函数判断联系人是否存在
    //1.存在--->根据返回的下标查找并打印出来
    //2.不存在--->说明要查找的联系人不存在
	contact* pos = FindByName(con, name);
	//判断是否存在
	if (pos == NULL)
	{
		printf("要查找的联系人不存在!\n");
		return 1;
	}
	else
	{
		printf("%-10s %-4s %-4s %15s %-20s\n", "姓名", "性别", "年龄", "联系电话", "地址");
		printf("%-10s %-4s %-4d %15s %-20s\n",//表头对齐--->美观
			pos->data.name,
			pos->data.sex,
			pos->data.age,
			pos->data.tel,
			pos->data.addr
		);
		printf("查找成功!\n");
	}
}
void ModifyByMenu()
{
	printf("*******************************************\n");
	printf("*******************通讯录******************\n");
	printf("***********1.修改姓名 2.修改性别***********\n");
	printf("***********3.修改年龄 4.修改号码***********\n");
	printf("***********5.修改地址 6.退出修改***********\n");
}

//修改通讯录数据
void ModifyContact(contact** con)
{
	//我们需要使用联系人众多信息中的一项来查找联系人是否存在
	//这里直接要求输入联系人的姓名进行查找
	//创建一个name数组存储要输入的姓名
	char name[NAME_MAX];
	printf("请输入要修改的联系人的姓名:");
	scanf("%s", &name);
	//调用函数判断联系人是否存在
	//1.存在--->根据返回的下标修改
	//2.不存在--->说明要修改的联系人不存在
	contact* pos = FindByName(*con, name);
	//判断是否存在
	if (pos == NULL)
	{
		printf("要修改的联系人不存在!\n");
		return 1;
	}
	else
	{
		int a = -1;
		do {
			ModifyByMenu();
			printf("请选择你的操作:");
			scanf("%d", &a);
			//底层逻辑是顺序表--->在顺序表中修改对应的下标的结构体中的各项数据
			switch (a)
			{
			case 1:
				printf("请输入新的联系人的姓名:");
				scanf("%s",pos->data.name);//name是数组名--->本来就是地址
				break;
			case 2:
				printf("请输入请输入新的联系人的性别:");
				scanf("%s", pos->data.sex);
				break;
			case 3:
				printf("请输入新的联系人的年龄:");
				scanf("%d", &pos->data.age);//age是int类型的数据--->取地址
				break;
			case 4:
				printf("请输入新的联系人的号码:");
				scanf("%s", pos->data.tel);
				break;
			case 5:
				printf("请输入新的联系人的地址:");
				scanf("%s", pos->data.addr);
				break;
			case 6:
				printf("退出修改联系人的界面!\n");
				break;
			default:
				printf("输入有误!请重新输入:");
				break;
			}
		} while (a != 6);
	}
}

//销毁通讯录数据

//先要保存文件的数据,再free
void SaveContact(contact* con)
{
	FILE* pf = fopen("contact.txt", "wb");
	if (pf == NULL)
	{
		perror("fopen error!\n");
		return 1;
	}
	//将通讯录的数据写入文件保存
	contact* cur = con;
	while (cur)
	{
		fwrite(&(cur->data), sizeof(cur->data), 1, pf);
		cur = cur->next;
	}
	
}
void DestroyContact(contact** con)
{
	SaveContact(*con);//传地址
	DestroyContact(con);
}

2.4 test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"SList.h"
#include"Contact.h"
//为了界面更加美观--->创建菜单界面
void menu1()
{
	printf("***********************************************\n");
	printf("*********************通讯录********************\n");
	printf("***********1.添加联系人 2.删除联系人***********\n");
	printf("***********3.修改联系人 4.查找联系人***********\n");
	printf("***********5.查看通讯录 6.退出通讯录***********\n");
}
int main()
{
	int a = -1;
	//初始化+创建通讯录
	contact* con=NULL;
	InitContact(&con);
	//一系列操作
	do {
		menu1();
		printf("请选择你的操作:\n");
		scanf("%d", &a);
		switch (a)
		{
		case 1:
			AddContact(&con);
			break;
		case 2:
			DelContact(&con);
			break;
		case 3:
			ModifyContact(&con);
			break;
		case 4:
			FindContact(con);
			break;
		case 5:
			ShowContact(con);
			break;
		case 6:
			printf("退出通讯录界面!\n");
			break;
		default:
			printf("选择错误!请重新选择:\n");
			break;
		}
	} while (a != 6);
	//销毁通讯录
	DestroyContact(&con);
	return 0;
}

2.5 最终效果呈现


本次的分享到这里就结束了!!!

PS:小江目前只是个新手小白。欢迎大家在评论区讨论哦!有问题也可以讨论的!

如果对你有帮助的话,记得点赞👍+收藏⭐️+关注➕

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

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

相关文章

云音乐Android Cronet接入实践

背景 网易云音乐产品线终端类型广泛&#xff0c;除了移动端&#xff08;IOS/安卓&#xff09;之外&#xff0c;还有PC、MAC、Iot多终端等等。移动端由于上线时间早&#xff0c;用户基数大&#xff0c;沉淀了一些端侧相对比较稳定的网络策略和网络基础能力。然而由于各端在基础…

AFsim编译-Windows

AFsim软件的核心应用及服务包括&#xff1a; sensor_plot&#xff1a;传感器覆盖和天线增益绘制工具&#xff1b; engage&#xff1a;武器交战分析工具&#xff1b; weapon_tools&#xff1a;武器建模工具&#xff1b; mission&#xff1a;任务仿真工具&#xff1b; post_…

3DCAT+东风日产:共建线上个性化订车实时云渲染方案

近年来&#xff0c;随着5G网络和云计算技术的不断发展&#xff0c;交互式3D实时云看车正在成为一种新的看车方式。 与传统的到4S店实地考察不同&#xff0c;消费者可以足不出户&#xff0c;通过网络与终端设备即可实现全方位展示、自选汽车配色、模拟效果、快捷选车并进行个性…

自动驾驶之—LaneAF学习相关总结

0.前言&#xff1a; 最近在学习自动驾驶方向的东西&#xff0c;简单整理一些学习笔记&#xff0c;学习过程中发现宝藏up 手写AI 1. 概述 Laneaf思想是把后处理放在模型里面。重点在于理解vaf&#xff0c; haf&#xff0c;就是横向聚类&#xff1a;中心点&#xff0c;纵向聚类&…

酷开科技依托酷开系统推动家庭智能化加速发展

为什么越来越多的人会选择智能家居&#xff1f;因为智能家居的出现&#xff0c;大大方便了我们的生活&#xff0c;为生活提供便利舒适的体验&#xff1b;就如同洗衣机与洗碗机解放了我们的双手是一样的道理&#xff0c;智能家居是在生活的方方面面为我们提供更加便利化的可能性…

基于Java的民宿酒店预约推广系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09; 代码参考数据库参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…

简单的谈谈VPN是什么、类型、使用场景以及工作原理?

作者&#xff1a;久孤776 个人主页&#xff1a;久孤776_python-CSDN博客 作者会持续更新网络知识以及关于python的知识期待你的关注 目录 一、vpn是什么 二、vpn的类型 1. 远程访问VPN 2. 点对点VPN 3. 入口站点VPN 4. 专线VPN 5. 客户端对站点VPN 三、VPN的使用场景 1…

GMT中标注特殊字符:平方,%,±号,希腊字母

在gmt中文社区的官网&#xff0c;我们可以得到以下的特殊字符表&#xff0c;通过在cmd命令窗口输入以下命令 gmt get PS_CHAR_ENCODING 查到你所安装的GMT的默认字符编码方式。如下图所示&#xff0c;本人是默认的ISOLation1 编码。 下面是一些具体的特殊字符的代码与标注效果…

【概率论教程01】对贝叶斯定理的追忆

一、说明 贝叶斯定理&#xff0c;是一个需要反复体悟的道理&#xff0c;不是说公式解释清除就算Grasp&#xff0c;而是需要反复在实际项目中发挥&#xff0c;才能算掌握了。而实际应用中&#xff0c;并不是简单给出条件就可以套用&#xff0c;而是隐藏在迷雾一样的事实中&#…

2016年亚太杯APMCM数学建模大赛B题化学元素对变形钢筋性能的影响求解全过程文档及程序

2016年亚太杯APMCM数学建模大赛 B题 化学元素对变形钢筋性能的影响 原题再现 热轧带肋钢筋通常被称为变形钢筋&#xff0c;它主要用于钢筋混凝土构件的骨架&#xff0c;在使用中需要一定的机械强度、弯曲和变形性能、制造焊接性。钢中的化学成分是影响热轧钢最终组织性能的基…

Java实现人脸识别和指纹认证

我们在开发中经常会有人脸识别的需求&#xff0c;今天就实现一个简单的人脸识别&#xff0c;调用的第三方SDK服务 0.先去注册服务 登录网址 虹软视觉开放平台—以免费人脸识别技术为核心的人脸识别算法开放平台 点击进行注册 进入之后新增我的服务 成功之后点击首页人脸识别…

『第四章』一见倾心:初识小雨燕(上)

在本篇博文中,您将学到如下内容: 1. 基本数据类型2. 基本操作符3. 枚举和结构4. 类和 Actor5. 属性、方法与访问控制6. 聚集总结夜月一帘幽梦,春风十里柔情。 无声交谈情意深,一见心曲绕梁成。 1. 基本数据类型 无论是 macOS 还是 iOS 上的开发,Swift 基础类型和功能都内置于…

Python+Requests+PyTest+Excel+Allure 接口自动化测试实战

目录 本文主要介绍了PythonRequessPyTestExcelAllure 接口自动化测试实战&#xff0c;文中通过示例代码介绍的非常详细&#xff0c;对大家的学习或者工作具有一定的参考学习价值&#xff0c;需要的朋友们下面随着小编来一起学习学习吧 Unittest是Python标准库中自带的单元测试…

​ iOS自动混淆测试处理笔记

1 打开 ipa&#xff0c;导出ipa 路径和配置文件路径会自动填充 ​ 2 点击 开始自动混淆测试处理 自动混淆测试是针对 oc 类和oc方法这两个模块进行自动混淆ipa&#xff0c;并ipa安装到设备中运行&#xff0c;通过检测运行ipa包是否崩溃&#xff0c;来对oc类和oc方法进行筛选。…

Java支付宝沙箱环境支付,官方Demo远程调试【内网穿透】

文章目录 前言1. 下载当面付demo2. 修改配置文件3. 打包成web服务4. 局域网测试5. 内网穿透6. 测试公网访问7. 配置二级子域名8. 测试使用固定二级子域名访问 前言 在沙箱环境调试支付SDK的时候&#xff0c;往往沙箱环境部署在本地&#xff0c;局限性大&#xff0c;在沙箱环境…

LUCEDA IPKISS------Definition Properties 表格查询

LUCEDA IPKISS------Definition Properties 表格查询

一文讲明白阿里云ace认证的含金量!

《中国云计算行业洞察与人才分析》显示&#xff0c;云计算领域人才月均薪酬在1W元以上的占比高达93.7%&#xff0c;3万元以上占比仍达24.7%。 相比之下&#xff0c;云计算人才远超互联网人才薪酬平均线&#xff0c;反映出市场对于其专业技术人才的需求。 云计算架构师、云计算…

【干货】JVS低代码表单基础组件的配置与应用

表单的基础组件主要用于收集用户输入的数据&#xff0c;并对这些数据进行验证和处理。通过表单组件&#xff0c;用户可以输入各种类型的数据&#xff0c;如文本、数字、日期、选择项等。这些数据可以通过表单的提交按钮提交到服务器进行处理&#xff0c;从而使网站或应用程序能…

【Docker】Docker Swarm介绍与环境搭建

为什么不建议在生产环境中使用Docker Compose 多机器如何管理&#xff1f;如何跨机器做scale横向扩展&#xff1f;容器失败退出时如何新建容器确保服务正常运行&#xff1f;如何确保零宕机时间&#xff1f;如何管理密码&#xff0c;Key等敏感数据&#xff1f; Docker Swarm介…

Istio实战(七)- Bookinfo 部署

1. Istio Bookinfo示例 1.1 部署Bookinfo # kubectl apply -f /apps/istio/samples/bookinfo/platform/kube/bookinfo.yaml -n hr1.2 确认Bookinfo已经部署正常 先确认以下pod和service已经被正确创建 # kubectl get pods -n hr NAME READY …