C++11 数据结构1 线性表的概念,线性表的顺序存储,实现,测试

一 线性表的概念

线性结构是一种最简单且常用的数据结构。

线性结构的基本特点是节点之间满足线性关系。

本章讨论的动态数组、链表、栈、队列都属于线性结构。

他们的共同之处,是节点中有且只有一个开始节点和终端节点。按这种关系,可以把它们的所有节点排列成一个线性序列。但是,他们分别属于几种不同的抽象数据类型实现,它们之间的区别,主要就是操作的不同。

线性表是零个或者多个数据元素的有限序列数据元素之间是有顺序的数据元素个数是有限的数据元素的类型必须相同

二 线性表的性质:

a)0 为性表的第一个元素,只有一个后继。
2)an 为线性表的最后一个元素,只有一个前驱。
3)除 a0 和 an 外的其它元素 ai,既有前驱,又有后继。
4)线性表能够逐项访问和顺序存取。

三 线性表顺序存储(动态数组)的设计与实现

采用顺序存储是表示线性表最简单的方法,具体做法是:将线性表中的元素一个接一个的存储在一块连续的存储区域中,这种顺序表示的线性表也成为顺序表。

1.设计底层实现

线性表的顺序存储,应该用数组的方式存储数据。

那么我们结合数组的方式想一下:应该怎么设计才合理。

        数组应该有限度,例如 int arr[10],表示该数组最多能容纳10个,我们称之为数组的能力。

        数组应该有实际存储的大小,例如 int arr[10],只有arr[0],arr[1]两个元素有值。该数组大小为2

        数组中的元素,应该是啥

                这个数组里面每一项的内容存储啥,底层是不知道的,底层设计应该是:不管上层存储啥,都可以,那么存储的就只能是万能指针(void *),为了记忆方便:我们用 SeqListNode表示void,typedef void SeqListNode;,因此 SeqListNode* 就是一个万能指针。

        那么底层的 struct 就应该出来了,注意这里,我们用

                capacity 表示数组的限度,

                length表示数组的实际大小,

                array表示指针数组:array是一个数组,数组的每一项都是一个指针,存放上层的存储的具体类型的首地址

typedef struct _tagseqlist {
	int capacity;
	int length;
	//int* array[];//那么这个数组应该多大才合理呢?显然,应该让使用者传递才合理,因此要换成下面的写法
	int ** array;
}TSeqList;

        数组应该有返回值,理论上应该是底层struct 的首地址。,我们还不应该让上层知道,底层的struct 具体是啥? 因此返回给上层的应该也是void *, 为了方便,使用 SeqList表示, typedef void SeqList;因此返回值应该是 SeqList*

2.底层应该给上层提供的interface思考:

给上层创建 list 的interface,user可以自己定义想要的list的大小。

这个底层要提供的肯定有 增删改查 功能

        也就是说:可以让上层存储一个具体类型的数据

        删除一个具体类型的数据

        查找某一个位置的具体的数据

        改动某一个位置的数据(本次具体的代码中并没有实现)

3.代码实现

公用的.h文件--001seqlist.h

        上层和底层公用的.h文件,这样说是因为,上层和底层有可能两个不同的公司,A公司买了B公司的产品,B是做底层的,要提供给A interface 和 动态库/静态库。因此这个interface是A和B 公用的。

#ifndef __001SEQLIST_H__

#define __001SEQLIST_H__

typedef void SeqList;
typedef void SeqListNode;

// 初始化,建立一个空的线性表 
//参数capacity表示该线性表的容量。
//返回值不为NULL,表示创建成功。
//返回值为NULL,表示创建失败。
SeqList* SeqList_Create(int capacity);

//销毁该线性表
//返回值为1,表示成功。
//返回值为-1,表示失败。
int SeqList_Destory(SeqList *list);

//清空seqlist
//返回值为1,表示成功。
//返回值为-1,表示失败。
int SeqList_Clear(SeqList *list);

// 返回线性表List存在的元素个数
//返回值 >=0 表示:该list存在的元素个数
//<0 表示error
int SeqList_Length(SeqList *list);


// 返回线性表List的元素能够存储元素的能力
//返回值 >0 表示:该list能够存储元素的能力
//<0 表示error
int SeqList_Capacity(SeqList *list);

//从seqlist 中获取指定位置的数据
//参数pos:seqlist中的位置
//返回值:为存储在该位置的元素
//返回NULL 表示有问题
SeqListNode* SeqList_Get(SeqList *list, int pos);


//给seqlist中指定位置插入数据,
//参数seqlistnode为要插入的数据
//参数 pos 为要插入的位置
//如果线性表中还有空间,但是指定的pos位置是大于 现在的length
//例如 线性表capacity为100,现在存储了20了,但是pos的值是50
//我们这里做work around,就会将数据插入到21的位置
//成功返回1
//失败 返回<0

int SeqList_Insert(SeqList *list,SeqListNode *node,int pos);


//从seqlist 中删除指定位置的元素
//参数 pos
//返回值为 删除的元素
//返回NULL 表示出现了error
SeqListNode* SeqList_Delete(SeqList *list ,int pos);

#endif

B公司具体的实现001seqlist.c

#include "001seqlist.h"
#include "stdio.h"
#include "stdlib.h"
#include <string.h>



//这个线性表中存储一个数组,而且数组的每一项应该都是一个地址
typedef struct _tagseqlist {
	int capacity;
	int length;
	//int* array[];//那么这个数组应该多大才合理呢?显然,应该让使用者传递才合理,因此要换成下面的写法
	int ** array;
}TSeqList;

// 初始化,建立一个空的线性表 
//参数capacity表示该线性表的容量。
//返回值,表示创建成功。
//返回值null,表示创建失败。
SeqList* SeqList_Create(int capacity) {
	TSeqList *tempseqlist = NULL;
	tempseqlist = malloc(sizeof(TSeqList));
	if (tempseqlist==NULL) {
		printf("SeqList_Create error tempseqlist==NULL\n");
		return NULL;
	}
	memset(tempseqlist,0,sizeof(TSeqList));
	tempseqlist->capacity = capacity;
	tempseqlist->length = 0;
	tempseqlist->array = (int **)malloc(sizeof(int*) * capacity);
	if (tempseqlist->array == NULL) {
		printf("SeqList_Create error tempseqlist->array==NULL\n");
		return NULL;
	}
	return tempseqlist;

}

//销毁该线性表
//返回值为1,表示成功。
//返回值为-1,表示失败。
int SeqList_Destory(SeqList *list)
{
	int ret = 1;
	if (list==NULL) {
		printf("SeqList_Destory error list==NULL\n");
		ret = -1;
		return ret;
	}

	TSeqList *tempseqlist = NULL;
	tempseqlist = (TSeqList *)list;

	if (tempseqlist->array != NULL) {
		free(tempseqlist->array);
		tempseqlist->array = NULL;
	}
	if (tempseqlist!=NULL) {
		free(tempseqlist);
		tempseqlist = NULL;
	}


	return ret;
}

//清空seqlist
//返回值为1,表示成功。
//返回值为-1,表示失败。
int SeqList_Clear(SeqList *list) {
	int ret = 1;
	if (list == NULL) {
		printf("SeqList_Clear error list==NULL\n");
		ret = -1;
		return ret;
	}

	TSeqList *tempseqlist = NULL;
	tempseqlist = (TSeqList *)list;
	tempseqlist->length = 0;
	return ret;
}

// 返回线性表List存在的元素个数
//返回值 >=0 表示:该list存在的元素个数
//<0 表示error
int SeqList_Length(SeqList *list) {
	int ret = 1;
	if (list == NULL) {
		printf("SeqList_Length error list==NULL\n");
		ret = -1;
		return ret;
	}

	TSeqList *tempseqlist = NULL;
	tempseqlist = (TSeqList *)list;
	return tempseqlist->length;
}


// 返回线性表List的元素能够存储元素的能力
//返回值 >0 表示:该list能够存储元素的能力
//<0 表示error
int SeqList_Capacity(SeqList *list) {
	int ret = 1;
	if (list == NULL) {
		printf("SeqList_Length error list==NULL\n");
		ret = -1;
		return ret;
	}

	TSeqList *tempseqlist = NULL;
	tempseqlist = (TSeqList *)list;
	return tempseqlist->capacity;
}

//从seqlist 中获取指定位置的数据
//参数pos:seqlist中的位置
//返回值:为存储在该位置的元素
//返回NULL 表示有问题
SeqListNode* SeqList_Get(SeqList *list, int pos) {
	SeqListNode *retSeqListNode = NULL;
	if (list == NULL) {
		printf("SeqList_Get error list==NULL\n");
		return retSeqListNode;
	}
	if (pos < 0) {
		printf("SeqList_Get error pos<0 pos = %d\n",pos);
		return retSeqListNode;
	}

	TSeqList *tempseqlist = NULL;
	tempseqlist = (TSeqList *)list;

	if (pos > tempseqlist->length - 1 ) {
		printf("SeqList_Get error pos > (tempseqlist->length - 1) pos = %d,tempseqlist->length = %d\n",
			pos, tempseqlist->length);
		return retSeqListNode;
	}
	SeqListNode *currentNode = NULL;
	return tempseqlist->array[pos];

}


//给seqlist中指定位置插入数据,
//参数seqlistnode为要插入的数据
//参数 pos 为要插入的位置
//如果线性表中还有空间,但是指定的pos位置是大于 现在的length
//例如 线性表capacity为100,现在存储了20了,但是pos的值是50
//我们这里做work around,就会将数据插入到21的位置
//成功返回1
//失败 返回<0

int SeqList_Insert(SeqList *list, SeqListNode *node, int pos) {
	int ret = 1;
	SeqListNode *retSeqListNode = NULL;
	if (list == NULL) {
		ret = -1;
		printf("SeqList_Insert error list==NULL ret = %d\n", ret);
		return ret;
	}
	if (node == NULL) {
		ret = -2;
		printf("SeqList_Insert error node==NULL ret = %d\n", ret);
		return ret;
	}
	if (pos < 0) {
		ret = -3;
		printf("SeqList_Insert error pos<0 pos = %d ret = %d\n", pos, ret);
		return ret;
	}

	TSeqList *tempseqlist = NULL;
	tempseqlist = (TSeqList *)list;

	//如果已经满了,就没办法插入了
	if (tempseqlist->capacity == tempseqlist->length) {
		ret = -4;
		printf("SeqList_Insert error pos<0 pos = %d ret =%d \n", pos, ret);
		return ret;
	}
	//work around ,假设capacity为100,length这时候为20,当pos>20,小于100时,将pos变成20
	//pos的值是从0开始,小于tempseqlist->capacity
	if (pos > (tempseqlist->length) && pos < (tempseqlist->capacity)) {
		printf("SeqList_Insert wrokaround (pos > (tempseqlist->length ) && pos < (tempseqlist->capacity)) pos = %d,tempseqlist->length = %d\n",
			pos, tempseqlist->length);
		pos = tempseqlist->length;
	}

	//正式插入数据,实际上就是将pos位置的数据往后移动,
	//注意的是:i的值我们赋的是 length,这时候 array[length]是没有值的,最后一个元素是array[length-1]
	//因此赋值是 tempseqlist->array[i] = tempseqlist->array[i-1];
	//当i>pos的最后一次执行完毕后,i会--。这时候i的值的就是pos位置的值的了,而这时候,判断不成立
	//因此这时候 i 的值就是pos的值,这时候再将 tempseqlist->array[i] = node
	int i = 0;
	for ( i = tempseqlist->length; i > pos;i--) {
		tempseqlist->array[i] = tempseqlist->array[i-1];
	}
	tempseqlist->array[i] = node;
	tempseqlist->length++;
	return ret;
}


//从seqlist 中删除指定位置的元素
//参数 pos
//返回值为 删除的元素
//返回NULL 表示出现了error
SeqListNode* SeqList_Delete(SeqList *list, int pos) {
	int ret = 1;
	SeqListNode *retSeqListNode = NULL;
	if (list == NULL) {
		ret = -1;
		printf("SeqList_Delete error list==NULL ret = %d\n", ret);
		return retSeqListNode;
	}
	if (pos < 0) {
		ret = -2;
		printf("SeqList_Delete error pos<0 pos = %d ret = %d\n", pos, ret);
		return retSeqListNode;
	}


	TSeqList *tempseqlist = NULL;
	tempseqlist = (TSeqList *)list;


	if (pos > tempseqlist->length-1) {
		ret = -3;
		printf("SeqList_Delete error because (pos > tempseqlist->length-1) pos = %d tempseqlist->length = %d ret =%d \n",
			pos, tempseqlist->length, ret);
		return retSeqListNode;
	}



	//先将要删除的节点缓存出来
	retSeqListNode = tempseqlist->array[pos];

	//
	int i = 0;
	for (i = pos+1; i < tempseqlist->length;++i) {
		tempseqlist->array[i-1] = tempseqlist->array[i];
	}
	tempseqlist->length--;
	return retSeqListNode;
}

核心的写法图示:

C公司使用

#define _CRT_SECURE_NO_WARNINGS
#include "stdio.h"
#include "stdlib.h"
#include "iostream"
using namespace std;

extern "C" {
#include "001seqlist.h"
}




typedef struct Teacher {
	int age;
	char name[128];
	char *othername;
	char **stuname; //一个老师下面有5个学生
}Teacher;

int main001() {

	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);//程序退出时检测内存泄漏并显示到“输出”窗口


	int ret = 0;
	SeqList* seqlist = NULL;

	// 初始化,建立一个空的线性表 
//参数capacity表示该线性表的容量。
//返回值为SeqList*,表示创建成功。
//返回值NULL,表示创建失败。
	seqlist =  SeqList_Create(100);
	if (seqlist==NULL) {
		ret = -1;
		printf("SeqList_Create(100) func error ret =%d\n", ret);
		return ret;
	}

	int listcapacity = SeqList_Capacity(seqlist);
	if (listcapacity < 0) {
		ret = -2;
		printf("SeqList_Capacity(seqlist) func error ret =%d listcapacity = %d\n", ret, listcapacity);
		return ret;
	}


	//给seqlist中指定位置插入数据,
	//参数seqlistnode为要插入的数据
	//参数 pos 为要插入的位置
	//如果线性表中还有空间,但是指定的pos位置是大于 现在的length
	//例如 线性表capacity为100,现在存储了20了,但是pos的值是50
	//我们这里做work around,就会将数据插入到21的位置
	//成功返回1
	//失败 返回<=0
	Teacher tea1;

	tea1.age = 11;

	strcpy(tea1.name, (const char*)"zhangsan");

	tea1.othername = (char *)malloc(sizeof(char) * 128);
	memset(tea1.othername, 0, sizeof(char)*128);
	strcpy(tea1.othername, (const char*)"zhangsanothername");

	tea1.stuname = (char **)malloc(sizeof(char *) * 5);
	memset(tea1.stuname, 0, sizeof(char *) * 5);
	for (size_t i = 0; i < 5; i++)
	{
		tea1.stuname[i] = (char *)malloc(sizeof(char) * 128);//每个学生名字也有128个字符
		memset(tea1.stuname[i], 0, sizeof(char)*128);
		sprintf(tea1.stuname[i],"zhangsanstuname%d",i+1);
	}
	


	Teacher tea2;

	tea2.age = 22;

	strcpy(tea2.name, (const char*)"lisi");

	tea2.othername = (char *)malloc(sizeof(char) * 128);
	memset(tea2.othername, 0, sizeof(char) * 128);
	strcpy(tea2.othername, (const char*)"lisiothername");

	tea2.stuname = (char **)malloc(sizeof(char *) * 5);
	memset(tea2.stuname, 0, sizeof(char *) * 5);
	for (size_t i = 0; i < 5; i++)
	{
		tea2.stuname[i] = (char *)malloc(sizeof(char) * 128);//每个学生名字也有128个字符
		memset(tea2.stuname[i], 0, sizeof(char) * 128);
		sprintf(tea2.stuname[i], "lisistuname%d", i + 1);
	}



	Teacher tea3;

	tea3.age = 33;

	strcpy(tea3.name, (const char*)"wangwu");

	tea3.othername = (char *)malloc(sizeof(char) * 128);
	memset(tea3.othername, 0, sizeof(char) * 128);
	strcpy(tea3.othername, (const char*)"wagnwuothername");

	tea3.stuname = (char **)malloc(sizeof(char *) * 5);
	memset(tea3.stuname, 0, sizeof(char *) * 5);
	for (size_t i = 0; i < 5; i++)
	{
		tea3.stuname[i] = (char *)malloc(sizeof(char) * 128);//每个学生名字也有128个字符
		memset(tea3.stuname[i], 0, sizeof(char) * 128);
		sprintf(tea3.stuname[i], "wangwustuname%d", i + 1);
	}



	ret =  SeqList_Insert(seqlist, &tea1, 0);
	if (ret<0) {
		printf("SeqList_Insert(seqlist, &tea1, 0) func error ret =%d \n", ret);
		return ret;
	}
	ret = SeqList_Insert(seqlist, &tea2, 0);
	if (ret < 0) {
		printf("SeqList_Insert(seqlist, &tea1, 0) func error ret =%d \n", ret);
		return ret;
	}
	ret = SeqList_Insert(seqlist, &tea3, 0);
	if (ret < 0) {
		printf("SeqList_Insert(seqlist, &tea1, 0) func error ret =%d \n", ret);
		return ret;
	}


	// 返回线性表List存在的元素个数
//返回值 >=0 表示:该list存在的元素个数
//<0 表示error
	int seqlistlength =  SeqList_Length(seqlist);
	if (seqlistlength < 0) {
		ret = seqlistlength;
		printf("SeqList_Length(seqlist) func error ret =%d \n", ret);
		return ret;
	}
	printf("seqlistlength = %d\n", seqlistlength);


	//从seqlist 中获取指定位置的数据
	//参数pos:seqlist中的位置
	//返回值:为存储在该位置的元素
	//返回NULL 表示有问题
	for (int i = 0; i < SeqList_Length(seqlist); i++)
	{
		Teacher* temptea = (Teacher *)SeqList_Get(seqlist, i);
		if (temptea ==NULL) {
			printf("can not get find teacher from pos = %d\n",i);
		}
		printf("temptea->age = %d,temptea->name = %s,temptea->othername=%s\n",
			temptea->age,
			temptea->name,
			temptea->othername);
		for (size_t j = 0; j < 5; j++)
		{
			printf("temptea->stuname[%d] = %s,  ",
				j, temptea->stuname[j]);
		}
		printf("\n");
	}


	//从seqlist 中删除指定位置的元素
	//参数 pos
	//返回值为 删除的元素
	//返回NULL 表示出现了error

	while (SeqList_Length(seqlist)>0) {
		Teacher* deltea = (Teacher *) SeqList_Delete(seqlist, 0);
		if (deltea == NULL) {
			printf("delete teacher from 0 error \n");
			break;
		}
		printf("deltea->age = %d,deltea->name = %s,deltea->othername=%s\n",
			deltea->age,
			deltea->name,
			deltea->othername);
		if(deltea->stuname!=NULL) {
			for (size_t i = 0; i < 5; i++)
			{
				if (deltea->stuname[i] != NULL) {
					printf("deltea->stuname[%d] = %s,  ",
						i,deltea->stuname[i]);
				}
			}
			cout << endl;
		}
		if (deltea->stuname != NULL) {
			for (size_t i = 0; i < 5; i++)
			{
				free(deltea->stuname[i]);
				deltea->stuname[i] = NULL;
			}
			free(deltea->stuname);
			deltea->stuname = NULL;
		}

		free(deltea->othername);
		deltea->othername = NULL;


		printf("\n");
	}
	


	//清空seqlist
//返回值为1,表示成功。
//返回值为-1,表示失败。
	ret = SeqList_Clear(seqlist);
	if (ret < 0) {
		printf("SeqList_Clear(seqlist) func error ret =%d \n", ret);
		return ret;
	}

	//销毁该线性表
//返回值为1,表示成功。
//返回值为-1,表示失败。
	ret = SeqList_Destory(seqlist);
	if (ret < 0) {
		printf("SeqList_Destory(seqlist) func error ret =%d \n", ret);
		return ret;
	}

	return 0;
}

注意的点:

上层在将数据delete 后,记得要free相关数据。
底层并不知道上层是什么样子的数据结构,因此只需要将自己malloc的数据清理就好。

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

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

相关文章

MC9S12A64 程序烧写方法

前言 工作需要对MC9S12A64 单片机进行程序烧写。 资料 MC9S12A64 单片机前身属于 飞思卡尔半导体&#xff0c;后来被恩智浦收购&#xff0c;现在属于NXP&#xff1b; MC9S12A64 属于16位S12系列&#xff1b;MC9S12 又叫 HCS12。 数据手册下载连接 S12D_16位微控制器 | N…

[大模型]TransNormerLLM-7B 接入 LangChain 搭建知识库助手

TransNormerLLM-7B 接入 LangChain 搭建知识库助手 环境准备 在 autodl 平台中租赁一个 3090/4090 等 24G 显存的显卡机器&#xff0c;如下图所示镜像选择 PyTorch–>2.0.0–>3.8(ubuntu20.04)–>11.8 接下来打开刚刚租用服务器的 JupyterLab&#xff0c;并且打开其…

简单实用的备忘录小工具 记事提醒备忘效果超好

在这个信息爆炸的时代&#xff0c;我们每个人都需要处理大量的信息和任务。有时候&#xff0c;繁忙的生活和工作会让我们感到压力山大。幸运的是&#xff0c;现在有很多简单实用的软件工具&#xff0c;像得力的小助手一样&#xff0c;帮助我们整理思绪&#xff0c;提高效率&…

Redis系列1:深刻理解高性能Redis的本质

1 背景 分布式系统绕不开的核心之一的就是数据缓存&#xff0c;有了缓存的支撑&#xff0c;系统的整体吞吐量会有很大的提升。通过使用缓存&#xff0c;我们把频繁查询的数据由磁盘调度到缓存中&#xff0c;保证数据的高效率读写。 当然&#xff0c;除了在内存内运行还远远不够…

Docker 和 Podman的区别

文章目录 Docker 和 Podman的区别安装架构和特权要求运行容器方面安全性(root的权限)镜像管理方面命令方面Docker常用命令Podman常用命令 Docker 和 Podman的区别 安装 Docker安装&#xff1a;官方文档 Podman安装&#xff1a;官方文档 架构和特权要求 Docker使用client-se…

11、电科院FTU检测标准学习笔记-越限及告警上送功能

作者简介&#xff1a; 本人从事电力系统多年&#xff0c;岗位包含研发&#xff0c;测试&#xff0c;工程等&#xff0c;具有丰富的经验 在配电自动化验收测试以及电科院测试中&#xff0c;本人全程参与&#xff0c;积累了不少现场的经验 ———————————————————…

git 快问快答

我在实习的时候&#xff0c;是用本地开发&#xff0c;然后 push 到 GitHub 上&#xff0c;之后再从 Linux 服务器上拉 GitHub 代码&#xff0c;然后就可以了。一般程序是在 Linux 服务器上执行的&#xff0c;我当时使用过用 Linux 提供的命令来进行简单的性能排查。 在面试的时…

详解爬虫基本知识及入门案列(爬取豆瓣电影《热辣滚烫》的短评 详细讲解代码实现)

目录 前言什么是爬虫&#xff1f; 爬虫与反爬虫基础知识 一、网页基础知识 二、网络传输协议 HTTP&#xff08;HyperText Transfer Protocol&#xff09;和HTTPS&#xff08;HTTP Secure&#xff09;请求过程的原理&#xff1f; 三、Session和Cookies Session Cookies Session与…

抖音小店流量差怎么办?做好这三大细节,就可以完美解决!

大家好&#xff0c;我是电商糖果 很多刚开店的朋友&#xff0c;遇到的第一个难题就是店铺流量差。 没有流量&#xff0c;也就不会出单&#xff0c;更别提起店了。 糖果做抖音小店四年多了&#xff0c;也开了很多家小店。 很多新店没有流量&#xff0c;其实主要原因是这三个…

在mysql函数中启动事物和行锁/悲观锁实现并发条件下获得唯一流水号

业务场景 我有一个业务需求&#xff1a;我有一个报卡表 report里面有一个登记号字段 fcardno、地区代码 faddrno和发病年份 fyear&#xff0c;登记号由**“4位地区代码”“00”“发病年份”“5位流水号”**组成&#xff0c;我要在每次插入一张报卡&#xff08;每一行数据&#…

【MATLAB源码-第46期】基于matlab的OFDM系统多径数目对比,有无CP(循环前缀)对比,有无信道均衡对比。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 OFDM&#xff08;正交频分复用&#xff09;是一种频域上的多载波调制技术&#xff0c;经常用于高速数据通信中。以下是关于多径数目、有无CP&#xff08;循环前缀&#xff09;以及有无信道均衡在OFDM系统中对误码率的影响&am…

自如电费均摊问题

3月份搬了次家&#xff0c;嫌麻烦租了自如&#xff0c;第一个月的电费账单出来了&#xff0c;由于我是中途搬进去的&#xff0c;于是乎就好奇他会如何计算均摊&#xff0c;这个月电费账单出来了&#xff0c;算了下发现了点东西。 先说结论&#xff1a;按照我的这个均摊的方式&a…

刻度清晰耐酸碱腐蚀PFA材质实验室用塑料量具特氟龙量筒量杯

PFA量筒为上下等粗的直筒状&#xff0c;特氟龙量杯是上大下小的圆台形&#xff0c;底座均有宽台设计&#xff0c;保证稳定性&#xff0c;两者均可在实验室中作为定量量取液体的量具&#xff0c;上沿一侧有弧嘴设计&#xff0c;便于流畅地倾倒液体。 规格参考&#xff1a;5ml、…

主线程捕获子线程异常

正常情况下使用多线程出现异常时&#xff0c;都是按照单个任务去处理异常&#xff0c;在线程间不需要通信的情况下&#xff0c;任务之间互不影响&#xff0c;主线程也不必知道子线程是否发成异常。 那么只需要处理子线程异常即可 Task.Run(() > {try{throw new Exception(&…

【Vision Pro应用】分享一个收集Apple Vision Pro 应用的网站

您是否也觉得 Vision Pro 应用程序商店经常一遍又一遍地展示相同的几个 VisionOS 应用程序?许多有趣、好玩的应用程序似乎消失得无影无踪,让人很难发现它们。为了帮助大家更轻松地探索和体验最新、最有趣的 Vision Pro 应用程序,这里分享一个网站https://www.findvisionapp.…

IDEA @Autowired不显示红线

IDEA 中&#xff0c;Autowired 显示红线一般情况是注入 Mapper 或者 Dao 时出现的&#xff0c;如下图&#xff1a; 这个报错是因为 Mapper 或者 Dao 上没有加 Repository 或者 Mapper&#xff0c;Autowired 注入时就判断为这不是一个 Bean。 不建议通过加上面两个注解的方式解…

Java面试八股之hashCode()和equals()方法的重要性

hashCode()和equals()方法的重要性 逻辑判断&#xff1a;equals()方法用于定义对象逻辑上的相等标准&#xff0c;即当两个对象在业务意义上被视为“相同”时&#xff0c;equals()应返回true。 哈希表支持&#xff1a;hashCode()返回一个整数哈希码&#xff0c;用于在哈希表&a…

【电路笔记】-数字逻辑门总结

数字逻辑门总结 文章目录 数字逻辑门总结1、概述2、逻辑门真值表3、总结 数字逻辑门有三种基本类型&#xff1a;与门、或门和非门。 1、概述 我们还看到&#xff0c;数字逻辑门具有与其相反或互补的形式&#xff0c;分别为“与非门”、“或非门”和“缓冲器”&#xff0c;并且…

AIGC的崛起:定义未来内容创作的新纪元

&#x1f31f;文章目录 &#x1f31f;AIGC简介&#x1f31f; AIGC的相关技术与特点&#x1f31f;AIGC有哪些应用场景&#xff1f;&#x1f31f;AIGC对其他行业影响&#x1f31f;面临的挑战与问题&#x1f31f;AIGC未来发展 &#x1f31f;AIGC十大热门网站推荐&#xff1a; 文心…

常用的7个免费ChatGPT网站

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…