C学习(数据结构)--> 实现顺序结构二叉树

news2024/9/29 21:18:58

目录

一、堆的概念与结构

 性质

二叉树的性质

二、堆的实现

1、结构

2、初始化与销毁

3、入堆与出堆(小堆)

1)Swap

2)入堆

1 数据的向上调整

2 入堆

3)出堆

1 数据的向下调整

 2 出堆

三、其他

1、入堆与出堆(大堆)

2、堆排序

1)排降序

 2)排升序

3、Top-K问题

四、总代码

Heap.h

Heap.cpp

main.cpp


一般堆使用顺序结构的数组来存储数据,堆是一种特殊的二叉树。具有二叉树的特性的同时,还具有其它的特性。

一、堆的概念与结构

如果有一个集合,把它所有的元素按完全二叉树的顺序存储方式存储,在一维数组中,并且每一个父节点小于它的孩子结点,则称这个完全二叉树为小堆,而称每一个父节点大于它的孩子结点的完全二叉树为大堆。

  • 小堆

  • 大堆 

 性质

根据以上可得,堆总是一棵完全二叉树,且堆中某个结点的值总是不大于或不小于父结点的值。

二叉树的性质

对于一个完全二叉树,按照从上至下从左至右的数组顺序对所有结点从0开始编号,那么对于序号为 i 的结点(i - 1)/ 2 对应的结点是它的父结点,2*i + 1 对应的结点是它的左孩子结点,2*i + 2 对应的结点是它的父结点

二、堆的实现

1、结构

typedef int HPDataType;
typedef struct Heap
{
	HPDataType* arr;
	int size;//有效数据个数
	int capacity;//空间大小
}Heap;

2、初始化与销毁

//堆的初始化
void HPInit(Heap* php)
{
	assert(php);
	php->arr = NULL;
	php->capacity = php->size = NULL;
}

//堆的销毁
void HPDestroy(Heap* php)
{
	assert(php);
	if (php->arr)
	{
		free(php->arr);
	}
	php->arr = NULL;
	php->capacity = php->size = NULL;
}

3、入堆与出堆(小堆)

1)Swap

通过Swap函数交换两个数据

//两个数据的交换
void Swap(HPDataType* x, HPDataType* y)
{
	assert(x || y);
	HPDataType cpy = *x;
	*x = *y;
	*y = cpy;
}

2)入堆

1 数据的向上调整

//数据的向上调整(小堆)
void AdjustUpSmall(HPDataType* arr, int child)
{
	assert(arr);
	int parent = (child - 1) / 2;//求该子节点的父结点
	while (child > 0)
	{
		if (arr[child] < arr[parent])//当孩子结点小于父节点时,两个数据交换
		{
			Swap(&arr[child], &arr[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}
2 入堆
//入堆(小堆)
void HPPushSmall(Heap* php, HPDataType x)
{
	assert(php);
	//判断空间是否足够
	if (php->capacity == php->size)
	{
		int newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;
		HPDataType* tmp = (HPDataType*)realloc(php->arr,sizeof(HPDataType) * newcapacity);
		if (tmp == NULL)
		{
			perror("realloc fali!!!");
			exit(1);
		}
		php->arr = tmp;
		php->capacity = newcapacity;
	}
	php->arr[php->size] = x;//因为数据还没有向上调整,所以size不能++
	//向上调整
	AdjustUpSmall(php->arr, php->size++);
}

3)出堆

1 数据的向下调整

//数据的向下调整(小堆)
void AdjustDownSmall(HPDataType* arr, int parent, int n)
{
	int child = parent * 2 + 1;//求该父节点的左孩子
	while (child < n)//该左孩子在数组内
	{
		if (child + 1 < n && arr[child] > arr[child + 1])//比较左右孩子大小
		{
			child++;
		}
		//父节点和孩子结点交换
		if (arr[child] < arr[parent])
		{
			Swap(&arr[child], &arr[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}
 2 出堆
//出堆(小堆)
void HPPopSmall(Heap* php)
{
	assert(php && php->size);//有效数据不能为零
	//头尾数据交换
	Swap(&php->arr[0], &php->arr[php->size - 1]);
	//出堆
	php->size--;
	//数据的向下调整
	AdjustDownSmall(php->arr, 0, php->size);
}

三、其他

1、入堆与出堆(大堆)

与小堆大同小异

//数据的向上调整(大堆)
void AdjustUpBig(HPDataType* arr, int child)
{
	assert(arr);
	int parent = (child - 1) / 2;//求该子节点的父结点
	while (child > 0)
	{
		if (arr[child] > arr[parent])
		{
			Swap(&arr[child], &arr[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

//入堆(大堆)
void HPPushBig(Heap* php, HPDataType x)
{
	assert(php);
	//判断空间是否足够
	if (php->capacity == php->size)
	{
		int newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;
		HPDataType* tmp = (HPDataType*)realloc(php->arr, sizeof(HPDataType) * newcapacity);
		if (tmp == NULL)
		{
			perror("realloc fali!!!");
			exit(1);
		}
		php->arr = tmp;
		php->capacity = newcapacity;
	}
	php->arr[php->size] = x;//因为数据还没有向上调整,所以size不能++
	//向上调整
	AdjustUpBig(php->arr, php->size++);
}

//数据的向下调整(大堆)
void AdjustDownBig(HPDataType* arr, int parent, int n)
{
	int child = parent * 2 + 1;//求该父节点的左孩子
	while (child < n)//该左孩子在数组内
	{
		if (child + 1 < n && arr[child] < arr[child + 1])//比较左右孩子大小
		{
			child++;
		}
		//父节点和孩子结点交换
		if (arr[child] > arr[parent])
		{
			Swap(&arr[child], &arr[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

//出堆(大堆)
void HPPopBig(Heap* php)
{
	assert(php && php->size);//有效数据不能为零
	//头尾数据交换
	Swap(&php->arr[0], &php->arr[php->size - 1]);
	//出堆
	php->size--;
	//数据的向下调整
	AdjustDownBig(php->arr, 0, php->size);
}

2、堆排序

1)排降序

 以排降序为例,通过建小堆来实现堆排序

void HeapSortSmall(int* arr, int n)
{
	建小堆,向上排序法建堆
	//for (int i = 0; i < n; i++)
	//{
	//	//向上建堆
	//	AdjustUpSmall(arr, i);
	//}
	//向下排序,建小堆
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)//(n - 1 - 1) / 2 求的是最底下子结点的父结点
	{
		AdjustDownSmall(arr, i, n);
	}
	//排降序
	int end = n - 1;
	while (end > 0)//出堆
	{
		Swap(&arr[0], &arr[end]);
		AdjustDownSmall(arr, 0, end);
		end--;
	}
}

 2)排升序

同理,通过建立大堆排升序

void HeapSortBig(int* arr, int n)
{
	//向下排序,建大堆
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)//(n - 1 - 1) / 2 求的是最底下子结点的父结点
	{
		AdjustDownBig(arr, i, n);
	}
	//排升序
	int end = n - 1;
	while (end > 0)
	{
		Swap(&arr[0], &arr[end]);
		AdjustDownBig(arr, 0, end);
		end--;
	}
}

3、Top-K问题

  • 问:有一个数据量特别大的集合,如何用一个最多包含 K 个元素的集合来求得最大或最小的前 K 个元素
  • 答:用前 K 个元素建大堆或小堆,在用剩余的N-K个元素依此与堆顶元素比较大小,如过该元素比堆顶元素大于或小于,则替换掉堆顶元素。
//造数据
void CreateNDate()
{
	int n = 100000;
	srand((unsigned int)time(NULL));
	const char* file = "data.txt";
	FILE* fin = fopen(file, "w");
	if (fin == NULL)
	{
		perror("fopen fail!!!");
		return;
	}
	for (int i = 0; i < n; i++)
	{
		int x = (rand() + i) % 1000000;
		fprintf(fin, "%d\n", x);
	}
	fclose(fin);
}

//Top-K 问题
void TopK()
{
	int k = 10;

	const char* file = "data.txt";
	FILE* fout = fopen(file, "r");
	if (fout == NULL)
	{
		perror("fopen fail!!!");
		exit(1);
	}

	int minHeap[10] = { 0 };
	
	//从文件中读前K个数据
	for (int i = 0; i < k; i++)
	{
		fscanf(fout, "&d\n", minHeap);
	}

	//建小堆
	for (int i = (k - 1 - 1) / 2; i > 0; i--)
	{
		AdjustDownSmall(minHeap, 0, k);
	}

	//继续取文件的数据,将读取到的数据和堆顶进行比较
	int x = 0;
	while (fscanf(fout, "%d", &x) != EOF)
	{
		if (x > minHeap[0])
		{
			minHeap[0] = x;
			AdjustDownSmall(minHeap, 0, k);
		}
	}

	//排升序
	printf("排升序:");
	HeapSortBig(minHeap, 10);
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", minHeap[i]);
	}
	printf("\n");

	fclose(fout);
}

四、总代码

Heap.h

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
#include<time.h>

typedef int HPDataType;
typedef struct Heap
{
	HPDataType* arr;
	int size;//有效数据个数
	int capacity;//空间大小
}Heap;
//堆的初始化
void HPInit(Heap* php);
//堆的销毁
void HPDestroy(Heap* php);
//两个数据的交换
void Swap(HPDataType* x, HPDataType* y);
//数据的向上调整(小堆)
void AdjustUpSmall(HPDataType* arr, int child);
//入堆(小堆)
void HPPushSmall(Heap* php, HPDataType x);
//数据的向下调整(小堆)
void AdjustDownSmall(HPDataType* arr, int parent, int n);
//出堆(小堆)
void HPPopSmall(Heap* php);
//判空
bool HPEmpty(Heap* php);
//取堆顶数据
HPDataType HPTop(Heap* php);
//数据的向上调整(大堆)
void AdjustUpBig(HPDataType* arr, int child);
//入堆(大堆)
void HPPushBig(Heap* php, HPDataType x);
//数据的向下调整(大堆)
void AdjustDownBig(HPDataType* arr, int parent, int n);
//出堆(大堆)
void HPPopBig(Heap* php);
//堆排序
//排升序,建大堆
//排降序,建小堆
void HeapSortSmall(int* arr, int n);
void HeapSortBig(int* arr, int n);

Heap.cpp

#include"Heap.h"

//堆的初始化
void HPInit(Heap* php)
{
	assert(php);
	php->arr = NULL;
	php->capacity = php->size = NULL;
}

//堆的销毁
void HPDestroy(Heap* php)
{
	assert(php);
	if (php->arr)
	{
		free(php->arr);
	}
	php->arr = NULL;
	php->capacity = php->size = NULL;
}

//两个数据的交换
void Swap(HPDataType* x, HPDataType* y)
{
	assert(x || y);
	HPDataType cpy = *x;
	*x = *y;
	*y = cpy;
}

//数据的向上调整(小堆)
void AdjustUpSmall(HPDataType* arr, int child)
{
	assert(arr);
	int parent = (child - 1) / 2;//求该子节点的父结点
	while (child > 0)
	{
		if (arr[child] < arr[parent])
		{
			Swap(&arr[child], &arr[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

//入堆(小堆)
void HPPushSmall(Heap* php, HPDataType x)
{
	assert(php);
	//判断空间是否足够
	if (php->capacity == php->size)
	{
		int newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;
		HPDataType* tmp = (HPDataType*)realloc(php->arr,sizeof(HPDataType) * newcapacity);
		if (tmp == NULL)
		{
			perror("realloc fali!!!");
			exit(1);
		}
		php->arr = tmp;
		php->capacity = newcapacity;
	}
	php->arr[php->size] = x;//因为数据还没有向上调整,所以size不能++
	//向上调整
	AdjustUpSmall(php->arr, php->size++);
}

//数据的向下调整(小堆)
void AdjustDownSmall(HPDataType* arr, int parent, int n)
{
	int child = parent * 2 + 1;//求该父节点的左孩子
	while (child < n)//该左孩子在数组内
	{
		if (child + 1 < n && arr[child] > arr[child + 1])//比较左右孩子大小
		{
			child++;
		}
		//父节点和孩子结点交换
		if (arr[child] < arr[parent])
		{
			Swap(&arr[child], &arr[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

//出堆(小堆)
void HPPopSmall(Heap* php)
{
	assert(php && php->size);//有效数据不能为零
	//头尾数据交换
	Swap(&php->arr[0], &php->arr[php->size - 1]);
	//出堆
	php->size--;
	//数据的向下调整
	AdjustDownSmall(php->arr, 0, php->size);
}

//判空
bool HPEmpty(Heap* php)
{
	assert(php);
	return php->size == 0;
}

//取堆顶数据
HPDataType HPTop(Heap* php)
{
	assert(php && php->size);
	return php->arr[0];
}

//数据的向上调整(大堆)
void AdjustUpBig(HPDataType* arr, int child)
{
	assert(arr);
	int parent = (child - 1) / 2;//求该子节点的父结点
	while (child > 0)
	{
		if (arr[child] > arr[parent])
		{
			Swap(&arr[child], &arr[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

//入堆(大堆)
void HPPushBig(Heap* php, HPDataType x)
{
	assert(php);
	//判断空间是否足够
	if (php->capacity == php->size)
	{
		int newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;
		HPDataType* tmp = (HPDataType*)realloc(php->arr, sizeof(HPDataType) * newcapacity);
		if (tmp == NULL)
		{
			perror("realloc fali!!!");
			exit(1);
		}
		php->arr = tmp;
		php->capacity = newcapacity;
	}
	php->arr[php->size] = x;//因为数据还没有向上调整,所以size不能++
	//向上调整
	AdjustUpBig(php->arr, php->size++);
}

//数据的向下调整(大堆)
void AdjustDownBig(HPDataType* arr, int parent, int n)
{
	int child = parent * 2 + 1;//求该父节点的左孩子
	while (child < n)//该左孩子在数组内
	{
		if (child + 1 < n && arr[child] < arr[child + 1])//比较左右孩子大小
		{
			child++;
		}
		//父节点和孩子结点交换
		if (arr[child] > arr[parent])
		{
			Swap(&arr[child], &arr[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

//出堆(大堆)
void HPPopBig(Heap* php)
{
	assert(php && php->size);//有效数据不能为零
	//头尾数据交换
	Swap(&php->arr[0], &php->arr[php->size - 1]);
	//出堆
	php->size--;
	//数据的向下调整
	AdjustDownBig(php->arr, 0, php->size);
}

//堆排序
//排升序,建大堆
//排降序,建小堆

void HeapSortSmall(int* arr, int n)
{
	建小堆,向上排序法建堆
	//for (int i = 0; i < n; i++)
	//{
	//	//向上建堆
	//	AdjustUpSmall(arr, i);
	//}
	//向下排序
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)//(n - 1 - 1) / 2 求的是最底下子结点的父结点
	{
		AdjustDownSmall(arr, i, n);
	}
	//排降序
	int end = n - 1;
	while (end > 0)
	{
		Swap(&arr[0], &arr[end]);
		AdjustDownSmall(arr, 0, end);
		end--;
	}
}
void HeapSortBig(int* arr, int n)
{
	//向下排序
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)//(n - 1 - 1) / 2 求的是最底下子结点的父结点
	{
		AdjustDownBig(arr, i, n);
	}
	//排升序
	int end = n - 1;
	while (end > 0)
	{
		Swap(&arr[0], &arr[end]);
		AdjustDownBig(arr, 0, end);
		end--;
	}
}

main.cpp

#include"Heap.h"

//造数据
void CreateNDate()
{
	int n = 100000;
	srand((unsigned int)time(NULL));
	const char* file = "data.txt";
	FILE* fin = fopen(file, "w");
	if (fin == NULL)
	{
		perror("fopen fail!!!");
		return;
	}
	for (int i = 0; i < n; i++)
	{
		int x = (rand() + i) % 1000000;
		fprintf(fin, "%d\n", x);
	}
	fclose(fin);
}

//Top-K 问题
void TopK()
{
	int k = 10;

	const char* file = "data.txt";
	FILE* fout = fopen(file, "r");
	if (fout == NULL)
	{
		perror("fopen fail!!!");
		exit(1);
	}

	int minHeap[10] = { 0 };
	
	//从文件中读前K个数据
	for (int i = 0; i < k; i++)
	{
		fscanf(fout, "&d\n", minHeap);
	}

	//建小堆
	for (int i = (k - 1 - 1) / 2; i > 0; i--)
	{
		AdjustDownSmall(minHeap, 0, k);
	}

	//继续取文件的数据,将读取到的数据和堆顶进行比较
	int x = 0;
	while (fscanf(fout, "%d", &x) != EOF)
	{
		if (x > minHeap[0])
		{
			minHeap[0] = x;
			AdjustDownSmall(minHeap, 0, k);
		}
	}

	//排升序
	printf("排升序:");
	HeapSortBig(minHeap, 10);
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", minHeap[i]);
	}
	printf("\n");

	fclose(fout);
}

void test01()
{
	Heap hpsmall;
	//堆的初始化
	HPInit(&hpsmall);
	//入堆(小堆)
	HPDataType arr[10] = { 32,11,55,223,86,123,867,3423,75,13 };
	for (int i = 0; i < 10; i++)
	{
		HPPushSmall(&hpsmall, arr[i]);
	}
	//取堆顶数据
	printf("Heap: ");
	while (!HPEmpty(&hpsmall))
	{
		printf("%d ", HPTop(&hpsmall));
		//出堆(小堆)
		HPPopSmall(&hpsmall);
	}
	printf("\n");
	//堆的销毁
	HPDestroy(&hpsmall);

	//排降序
	printf("排降序:");
	HeapSortSmall(arr, 10);
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");

	//排升序
	printf("排升序:");
	HeapSortBig(arr, 10);
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");

	//CreateNDate();
	TopK();
}

int main()
{
	test01();
	return 0;
}

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

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

相关文章

解决Github无法连接codespace情况

使用这个DNS即可 CN - 中国互联网络信息中心CNNIC SDNS1.2.4.8,,True 参见&#xff1a; GitHub 无法访问解决办法 - 哔哩哔哩

一些可以参考的文档集合17

应用运行主目录 之前的文章集合: 一些可以参考文章集合1_xuejianxinokok的博客-CSDN博客 一些可以参考文章集合2_xuejianxinokok的博客-CSDN博客 一些可以参考的文档集合3_xuejianxinokok的博客-CSDN博客 一些可以参考的文档集合4_xuejianxinokok的博客-CSDN博客 一些可以…

乱弹篇(42)处暑与吃秋

“太热了。8点收竿&#xff0c;匆忙回家降温。”刚才完笔者把这话发给了微信亲友。 书画家黄老弟回复&#xff1a;“又是保长吧&#xff1f;天热了&#xff0c;鱼不出来。下次努力。” 知友家乡兰回复&#xff1a;“是啊&#xff0c;自贡已达40度&#xff01;” 在“电老虎”…

为什么录屏没有声音?教你三招,解决系统与麦克风声音录制技巧

电脑录屏声音同步技巧&#xff1a;系统与麦克风声音录制 在游戏录制和微课制作中&#xff0c;音画同步是保证观众体验的关键因素。无论是紧张刺激的游戏解说&#xff0c;还是知识传递的微课讲解&#xff0c;清晰同步的声音都能让内容更加生动&#xff0c;更能吸引观众的注意力…

【UE5.1】NPC人工智能——06 NPC攻击

目录 前言 效果 步骤 一、准备NPC狮子攻击的动画 二、NPC狮子攻击玩家造成伤害 前言 在上一篇中&#xff08;【UE5.1】NPC人工智能——05 给NPC添加视觉感知&#xff09;我们已经给NPC添加了感知功能&#xff0c;使其在感知到玩家后就跑向玩家。本篇要实现的功能是&#x…

赛力斯汽车改名问界汽车,字号随着商标改!

从国家企业信用网显示&#xff0c;近日赛力斯汽车企业名称变更为重庆问界汽车&#xff0c;以前余承东直播&#xff0c;谈到问界等商标品牌的转让&#xff0c;问界品牌价值至少100亿&#xff0c;赛力斯最终是25亿收购华为“问界”商标&#xff0c;估值102亿。 经常遇到有人问&am…

代码随想录Day 22| 回溯算法开篇,77.组合、216组合总和Ⅲ、17.电话号码的字母组合

提示&#xff1a;DDU&#xff0c;供自己复习使用。欢迎大家前来讨论~ 文章目录 回溯算法理论基础一、理论基础1.1 什么是回溯法1.2 回溯法的效率1.3 回溯法解决的问题1.4 如何理解回溯法1.5 回溯法模板 二、题目题目一&#xff1a;77.组合解题思路&#xff1a;回溯法三部曲组合…

碎碎念:关于小模型或者端侧大模型

今年有个有趣的现象&#xff0c;大厂分别推出能够在端侧运行的小模型 Microsoft&#xff1a;Phi-3 Vision 4.2b&#xff0c;支持 文本、图像输入&#xff0c;可以运行在 surface 上 Google&#xff1a;Gemini Nano 1.8b/3.2b&#xff0c;支持文本&#xff0c;可以运行在手机上…

SwiftUI 如何恣意定制和管理系统中的窗口(Window)

概览 在苹果大屏设备上,我们往往需要借助多窗口(Multiwindow)来充分利用海量的显示空间,比如 Mac,iPad 以及 AppleTV 系统 等等。 所幸的是,SwiftUI 对多窗口管理提供了很好的支持。利用 SwiftUI 我们可以非常轻松的设置窗口在屏幕上的位置,大小以及拖动反馈。 在本篇…

新版干货|互联网算法备案办理指南

一、什么是互联网算法备案 根据《互联网信息服务算法推荐管理规定》《互联网信息服务深度合成管理规定》和《生成式人工只能服务管理暂行办法》相关规定&#xff0c;需要进行互联网算法备案的主体包含具有舆论属性或者社会动员能力的算法推荐服务提供者、深度合成服务提供者、…

第五节:Nodify 节点位置设置

引言 如果你尝试过前几节的代码&#xff0c;会发现节点都是出现在0,0 位置&#xff0c;及编辑器左上角。编辑器作为最外层的交互控件&#xff0c;内部封装了节点容器ItemContrainer&#xff0c;我们通过样式属性对Loaction做绑定。本节将介绍如何配置节点位置。 1、节点位置 …

FPGA实现TMDS编码

1.TMDS编码 TMDS&#xff08;Transition Minimized Differential Signaling&#xff09;&#xff0c;即最小化差分传输信号&#xff0c;在DVI&#xff08;数字视频接口&#xff0c;只能传输视频&#xff09;和HDMI&#xff08;音视频均可传输&#xff09;协议中用于传输音视频…

适用于 Windows 的典型 PDF 编辑器程序

尽管 PDF 文件已经存在了很长时间&#xff0c;但我们仍然希望使用此类文件完成一些任务。其中一项任务是在我们的计算机上编辑它们&#xff0c;尤其是 Windows。但是&#xff0c;考虑到 PDF 文件是复杂数据的集合&#xff0c;它不会那么简单。因此&#xff0c;您将需要第三方应…

5分钟就能搭建 AI 聊天室场景!内含源代码,码住了!

近期奥运会的赛事观看火爆全网&#xff0c;大家在赛事直播间的聊天更是异常活跃&#xff0c;小编作为一个非足球爱好者&#xff0c;经常对直播解说中的「专有名词」充满迷惑。这时候特别想有一个 AI 数字人帮忙解惑。 这里&#xff0c;我们就利用云信的 AI 数字人&#xff0c;…

GraphRAG + Ollama 本地部署全攻略:避坑实战指南

—1— 为什么要对 GraphRAG 本地部署&#xff1f; 微软开源 GraphRAG 后&#xff0c;热度越来越高&#xff0c;目前 GraphRAG 只支持 OpenAI 的闭源大模型&#xff0c;导致部署后使用范围大大受限&#xff0c;本文通过 GraphRAG 源码的修改&#xff0c;来支持更广泛的 Embedd…

springboot之项目搭建并say hi

写在前面 本文看下如何搭建一个最简单的支持http接口的hello程序。 1&#xff1a;正文 接着引入springboot依赖&#xff1a; <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><v…

4.7重复的子字符串(LC_459-E)

给定一个非空的字符串 s &#xff0c;检查是否可以通过由它的一个子串重复多次构成。 示例 1: 输入: s "abab" 输出: true 解释: 可由子串 "ab" 重复两次构成。示例 2: 输入: s "aba" 输出: false示例 3: 输入: s "abcabcabcabc"…

无线终端ZWS云应用(一)—1分钟快速接入CATCOM-100 DTU上云

环境监测设备&#xff08;如温湿度传感器&#xff09;可以通过DTU终端CATCOM-100接入ZWS云平台&#xff0c;实现远程监控和管理。 准备工作 准备一个温湿度传感器和一个致远电子的DTU终端CATCOM-100。准备一张SIM卡&#xff0c;用于4G联网。 操作步骤 1. 云平台设备创建 1.1 …

PCIe563XD系列多功能异步数据采集卡64路AD信号采集500K采样频率

阿尔泰科技 型号&#xff1a;PCIe5630D/5631D/5632D/5633Dhttps://item.taobao.com/item.htm?spma1z10.3-c-s.w4002-265216876.12.84513350msbilC&id589158158140&piskf6qstfsYFCA6dK09z-BERdlfDjobG5szWKMYE-KwHcntcqeoOlla3juYGWce0OmNomNjOScZ7chwcmwbiSuY0jrXIkN…