手撕顺序表

news2024/9/23 13:21:37

> 作者简介:დ旧言~,目前大一,现在学习Java,c,c++,Python等
> 座右铭:松树千年终是朽,槿花一日自为荣。
> 望小伙伴们点赞👍收藏✨加关注哟💕💕       

 🌟前言       

        梦回数组,当我们开辟了一个数组,数组的大小就已经确定了,不能括容,也不能减容,为了解决这个问题,在数据结构有一个这样的知识--《顺序表》。顺序表连续开辟一个空间,能括容,也能减容,今天我们手撕顺序表。

🌙主体

咱们从三个方面实现顺序表,动态管理,头插头删尾插尾删,增删查改。

在程序中为了实现顺序表,需要创建头文件SeqList.h ,创建源文件test.c,SeqList.c。

 🌠动态管理

💤初始化动态顺序表

  1. 首先定义一个结构体(在源文件中),结构体里面有可变数组(a),数组初始长度(size),初始空间(capacity)。
  2. 初始化动态顺序表(SeqList.h中),需要开辟空间,再判断空间是否为空,再初始化数组长度,空间。
//动态顺序表
typedef int SLDataType;
typedef struct SeqList
{
	 //定义一个可变数组
	SLDataType* a;
	 //定义数组初始长度
	 int size;
	 //定义空间大小
	 int capacity;
}SL;


//初始化动态顺序表
void SLInit(SL* ps)
{
	//开辟空间
	ps->a = (SLDataType*)malloc(sizeof(SLDataType*) * 4);
	//判断空间是否为空
	if (ps->a == NULL)
	{
		perror("malloc failed");
		exit(-1);
	}
	//初始化
	ps->size = 0;
	ps->capacity = 4;
}

1.防止一直创建结构体,为了一劳永逸,我们把动态顺序表放在源文件中。

2.这里我们用typedef int SLDataType,给数据类型重定义名字,这样就可以防止修改数据类型。

💤扩容顺序表空间

数组初始长度(size),初始空间(capacity)相同时,这里们就需要扩容,这里我们扩容两倍。(在头文件中SeqList.h中)

//扩容空间
void SLCheckCapacity(SL* ps)
{
	//如果size和capacity相同
	if (ps->size == ps->capacity)
	{
		//扩大两倍
		SLDataType* tmp = (SLDataType*)realloc(ps->a, ps->capacity * 2 * sizeof(SLDataType));
		//判断tmp是否为空
		if (tmp == NULL)
		{
			perror("realloc failed");
			exit(-1);
		}
		//赋值
		ps->a = tmp;
		ps->capacity = ps->capacity * 2;
	}
}

💤释放顺序表内存

可变数组(a)置为(NULL),数组长度(size)置为(0),初始空间(capacity)置为(0)。

//释放内存
void SLDestroy(SL* ps)
{
	//断言
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->size = 0;
	ps->capacity = 0;
}

 🌠头插头删尾插尾删

💤添加元素

首先需要断言防止顺序表为空。这里需要注意空间是否满了。这里的实现和在pos位置插入x有类似,等我们实现这个函数,就可以直接调用这个函数,更加简便。(在头文件中SeqList.h中)

//添加元素
void SLPushBack(SL* ps, SLDataType x)
{
	//断言
	assert(ps);
	//判断空间是否满了,需要调用函数
	SLCheckCapacity(ps);
	//添加元素
	ps->a[ps->size] = x;
	ps->size++;

	//在pos位置插入x
	//SLInsert(ps, ps->size, x);
}

💤打印元素

打印元素太简单啦,直接用for循环就行。(在头文件中SeqList.h中)

//打印数组
void SLPrint(SL* ps) 
{
	for (int i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->a[i]);
	}
	printf("\n");
}

💤尾删

直接在末尾删除就行,之后这里只要size减减就好了,后面的元素会覆盖。这里的实现和在pos位置插入x有类似,等我们实现这个函数,就可以直接调用这个函数,更加简便。(在头文件中SeqList.h中)

//尾删
void SLPopBack(SL* ps)
{
	//断言
	assert(ps);
	// 温柔的检查
	//if (ps->size == 0)
		//return;

	// 暴力的检查
	assert(ps->size > 0);

	//ps->a[ps->size - 1] = 0;
	
	//这里只要size减减就好了,后面的元素会覆盖
	ps->size--;

	//删除pos位置的值
	//SLErase(ps, ps->size - 1);
}

💤头插(重点)

这里需要注意要让ps->size加加这里的实现和在pos位置插入x有类似,等我们实现这个函数,就可以直接调用这个函数,更加简便。(在头文件中SeqList.h中)

//头插
void SLPushFront(SL* ps, SLDataType x)
{
	//断言
	assert(ps);

	//定义最后一个元素
	int end = ps->size - 1;
	//循环
	while (end >= 0)
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}
	//x赋给最前的数字
	ps->a[0] = x;
	//指向下一个数字
	ps->size++;

	//在pos位置插入x
	//SLInsert(ps, 0, x);
}

💤头删(重点)

这里需要注意要让ps->size减减这里的实现和删除pos位置的值相似,等我们实现这个函数,就可以直接调用这个函数,更加简便。(在头文件中SeqList.h中)

//头删
void SLPopFront(SL* ps)
{
	//断言
	assert(ps);

	//断言(指向不能为零)
	assert(ps);
	//指向头前面的那个数字
	int begin = 1;
	//循环
	while (begin < ps->size)
	{
		ps->a[begin - 1] = ps->a[begin];
		begin++;
	}
	ps->size--;

	//删除pos位置的值
	//SLErase(ps, 0);
}

  🌠增删查改

💤在pos位置插入x

首先这里需要判断pos是否在数组空间内,其次判断空间是否充足,然后循环,最后ps->size++

这里的插入本质和头插相似。(元素向后移动一格)

//在pos位置插入x
void SLInsert(SL* ps, int pos, SLDataType x)
{
	//断言,这里pos
	assert(ps);
	assert(pos >= 0 && pos < ps->size);
	//内存不够需要括容
	SLCheckCapacity(ps);
	int end = ps->size - 1;
	while (end >= pos)
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}
	ps->a[pos] = x;
	ps->size++;
}

💤删除pos位置的值

首先这里需要判断pos是否在数组空间内,其次判断空间是否充足,然后循环,最后ps->size--

这里的删除本质和头删相似。(元素向前移动一格)

//删除pos位置的值
void SLErase(SL* ps, int pos)
{
	//断言
	assert(ps);
	//断言pos
	assert(pos >= 0 && pos < ps->size);
	int begin = pos + 1;
	while (begin < ps->size)
	{
		ps->a[begin - 1] = ps->a[begin];
		++begin;
	}
	ps->size--;
}

 💤修改pos位置的信息

这个实现太简单啦。

//修改pos位置的信息
void SLModify(SL* ps, int pos, SLDataType x)
{
	//断言
	assert(ps);
	//判断pos
	assert(pos >= 0 && pos < ps->size);
	//直接换
	ps->a[pos] = x;
}

🌠主函数

int main()
{
    //定义结构体
	SL sl;
	//初始动态列表
	SLInit(&sl);
	//释放内存
	SLDestroy(&sl);
    return 0;
}

🌙代码总结

🌠主函数

//主函数(包含头文件)
#include"SeqList.h"

//尾删
void TestSeqList1()
{
	//定义结构体
	SL sl;
	//初始化
	SLInit(&sl);
	//添加元素
	SLPushBack(&sl, 1);
	SLPushBack(&sl, 2);
	SLPushBack(&sl, 3);
	SLPushBack(&sl, 4);
	SLPushBack(&sl, 5);
	SLPushBack(&sl, 6);
	SLPushBack(&sl, 6);
	SLPushBack(&sl, 0);
	SLPushBack(&sl, 0);
	//打印元素
	SLPrint(&sl);
	//尾删
	SLPopBack(&sl);
	SLPopBack(&sl);
	//打印元素
	SLPrint(&sl);
	//尾删
	SLPopBack(&sl);
	SLPopBack(&sl);
	SLPopBack(&sl);
	SLPopBack(&sl);
	SLPopBack(&sl);
	SLPopBack(&sl);
	SLPopBack(&sl);
	//打印元素
	SLPrint(&sl);
	//添加元素
	SLPushBack(&sl, 1);
	SLPushBack(&sl, 2);
	//打印元素
	SLPrint(&sl);
	//释放内存
	SLDestroy(&sl);
}

//头删
void TestSeqList2()
{
	//定义结构体
	SL sl;
	//初始动态列表
	SLInit(&sl);
	//添加元素
	SLPushBack(&sl, 1);
	SLPushBack(&sl, 2);
	SLPushBack(&sl, 3);
	SLPushBack(&sl, 4);
	SLPushBack(&sl, 5);
	//打印元素
	SLPrint(&sl);
	//头插
	SLPushFront(&sl, 10);
	SLPushFront(&sl, 20);
	SLPushFront(&sl, 30);
	SLPushFront(&sl, 40);
	//头删
	SLPopFront(&sl);
	SLPopFront(&sl);
	SLPopFront(&sl);
	//打印元素
	SLPrint(&sl);
	//释放内存
	SLDestroy(&sl);
}

//在pos位置插入x
void TestSeqList3()
{
	//定义结构体
	SL sl;
	//初始动态列表
	SLInit(&sl);
	//添加元素
	SLPushBack(&sl, 1);
	SLPushBack(&sl, 2);
	SLPushBack(&sl, 3);
	SLPushBack(&sl, 4);
	SLPushBack(&sl, 5);
	//打印元素
	SLPrint(&sl);
	//在pos位置插入x
	int input = 0;
	printf("请输入插入的位置:");
	scanf("%d", &input);
	int number = 0;
	printf("请输入插入的数字:");
	scanf("%d", &number);
	SLInsert(&sl, input, number);
	//打印元素
	SLPrint(&sl);
	//释放内存
	SLDestroy(&sl);
}

//删除pos位置的值
void TestSeqList4()
{
	//定义结构体
	SL sl;
	//初始动态列表
	SLInit(&sl);
	//添加元素
	SLPushBack(&sl, 1);
	SLPushBack(&sl, 2);
	SLPushBack(&sl, 3);
	SLPushBack(&sl, 4);
	SLPushBack(&sl, 5);
	//打印元素
	SLPrint(&sl);
	//删除pos位置的值
	int input = 0;
	printf("请输入删除的位置:");
	scanf("%d", &input);
	SLErase(&sl, input);
	//打印元素
	SLPrint(&sl);
	//释放内存
	SLDestroy(&sl);
}

//删除pos位置的值
void TestSeqList5()
{
	//定义结构体
	SL sl;
	//初始动态列表
	SLInit(&sl);
	//添加元素
	SLPushBack(&sl, 1);
	SLPushBack(&sl, 2);
	SLPushBack(&sl, 3);
	SLPushBack(&sl, 4);
	SLPushBack(&sl, 5);
	//打印元素
	SLPrint(&sl);
	//修改pos位置的信息
	int input = 0;
	printf("请输入需要修改的位置:");
	scanf("%d", &input);
	int number = 0;
	printf("请输入需要修改的数字:");
	scanf("%d", &number);
	SLModify(&sl, input, number);
	//打印元素
	SLPrint(&sl);
	//释放内存
	SLDestroy(&sl);
}

int main()
{

	//TestSeqList1();
	//TestSeqList2();
	//TestSeqList3();
	//TestSeqList4();
	TestSeqList5();
	return 0;
}

🌠SeqList.h源文件

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

//动态顺序表
typedef int SLDataType;
typedef struct SeqList
{
	 //定义一个可变数组
	SLDataType* a;
	 //定义数组初始长度
	 int size;
	 //定义空间大小
	 int capacity;
}SL;

//动态管理
//初始化动态顺序表
void SLInit(SL* ps);
//释放内存
void SLDestroy(SL* ps);
//打印数组
void SLPrint(SL* ps);
//扩容空间
void SLCheckCapacity(SL* ps);

// 头插头删 尾插尾删
void SLPushBack(SL* ps, SLDataType x);//添加元素
void SLPopBack(SL* ps);//尾删
void SLPushFront(SL* ps, SLDataType x);//头插元素
void SLPopFront(SL* ps);//头删

//返回下标,没有找打返回-1
int SLFind(SL* ps, SLDataType x);
//在pos位置插入x
void SLInsert(SL* ps, int pos, SLDataType x);
//删除pos位置的值
void SLErase(SL* ps, int pos);
//修改pos位置的信息
void SLModify(SL* ps, int pos, SLDataType x);

🌠SeqList.c头文件

#include"SeqList.h"

//初始化动态顺序表
void SLInit(SL* ps)
{
	//开辟空间
	ps->a = (SLDataType*)malloc(sizeof(SLDataType*) * 4);
	//判断空间是否为空
	if (ps->a == NULL)
	{
		perror("malloc failed");
		exit(-1);
	}
	//初始化
	ps->size = 0;
	ps->capacity = 4;
}

//释放内存
void SLDestroy(SL* ps)
{
	//断言
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->size = 0;
	ps->capacity = 0;
}

//打印数组
void SLPrint(SL* ps) 
{
	for (int i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->a[i]);
	}
	printf("\n");
}

//扩容空间
void SLCheckCapacity(SL* ps)
{
	//如果size和capacity相同
	if (ps->size == ps->capacity)
	{
		//扩大两倍
		SLDataType* tmp = (SLDataType*)realloc(ps->a, ps->capacity * 2 * sizeof(SLDataType));
		//判断tmp是否为空
		if (tmp == NULL)
		{
			perror("realloc failed");
			exit(-1);
		}
		//赋值
		ps->a = tmp;
		ps->capacity = ps->capacity * 2;
	}
}

//添加元素
void SLPushBack(SL* ps, SLDataType x)
{
	//断言
	assert(ps);
	/*//判断空间是否满了,需要调用函数
	SLCheckCapacity(ps);
	//添加元素
	ps->a[ps->size] = x;
	ps->size++;*/

	//在pos位置插入x
	SLInsert(ps, ps->size, x);
}

//尾删
void SLPopBack(SL* ps)
{
	//断言
	assert(ps);
	/*// 温柔的检查
	//if (ps->size == 0)
		//return;

	// 暴力的检查
	assert(ps->size > 0);

	//ps->a[ps->size - 1] = 0;
	
	//这里只要size减减就好了,后面的会覆盖
	ps->size--;*/

	//删除pos位置的值
	SLErase(ps, ps->size - 1);
}

//头插
void SLPushFront(SL* ps, SLDataType x)
{
	//断言
	assert(ps);

	/*//定义最后一个元素
	int end = ps->size - 1;
	//循环
	while (end >= 0)
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}
	//x赋给最前的数字
	ps->a[0] = x;
	//指向下一个数字
	ps->size++;*/

	//在pos位置插入x
	SLInsert(ps, 0, x);
}

//头删
void SLPopFront(SL* ps)
{
	//断言
	assert(ps);

	/*//断言(指向不能为零)
	assert(ps);
	//指向头前面的那个数字
	int begin = 1;
	//循环
	while (begin < ps->size)
	{
		ps->a[begin - 1] = ps->a[begin];
		begin++;
	}
	ps->size--;*/

	//删除pos位置的值
	SLErase(ps, 0);
}

//返回下标,没有找打返回-1
int SLFind(SL* ps, SLDataType x)
{
	//断言
	assert(ps);
	//遍历
	for (int i = 0; i < ps->size; i++)
	{
		if (ps->a[i] == x)
		{
			return i;
		}
	}
	return -1;
}

//在pos位置插入x
void SLInsert(SL* ps, int pos, SLDataType x)
{
	//断言,这里pos
	assert(ps);
	assert(pos >= 0 && pos < ps->size);
	//内存不够需要括容
	SLCheckCapacity(ps);
	int end = ps->size - 1;
	while (end >= pos)
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}
	ps->a[pos] = x;
	ps->size++;
}

//删除pos位置的值
void SLErase(SL* ps, int pos)
{
	//断言
	assert(ps);
	//断言pos
	assert(pos >= 0 && pos < ps->size);
	int begin = pos + 1;
	while (begin < ps->size)
	{
		ps->a[begin - 1] = ps->a[begin];
		++begin;
	}
	ps->size--;
}

//修改pos位置的信息
void SLModify(SL* ps, int pos, SLDataType x)
{
	//断言
	assert(ps);
	//判断pos
	assert(pos >= 0 && pos < ps->size);
	//直接换
	ps->a[pos] = x;
}

🌟结束语

今天内容就到这里啦,时间过得很快,大家沉下心来好好学习,会有一定的收获的,大家多多坚持,嘻嘻,成功路上注定孤独,因为坚持的人不多。那请大家举起自己的小说手给博主一键三连,有你们的支持是我最大的动力💞💞💞,回见。

 

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

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

相关文章

标准IO_文件读写_fgetc,getchar,ungetc,fgets,fputs,fread,fwrite

目录 1.单字符文件读写 1.1 单字符读文件 1.1.1 fgetc函数 1.1.2 getc函数 1.1.3 getchar函数 1.1.4 ungetc函数 1.1.5 单字符读文件综合示例代码 1.2 单字符写文件 1.2.1 fputc函数 1.2.2 putc函数 1.2.3 putchar函数 1.2.4 单字符写文件综合示例代码 2.多字符文…

c++11 标准模板(STL)(std::basic_filebuf)(七)

定义于头文件 <fstream> template< class CharT, class Traits std::char_traits<CharT> > class basic_filebuf : public std::basic_streambuf<CharT, Traits> std::basic_filebuf 是关联字符序列为文件的 std::basic_streambuf 。输入序…

python核心-面向对象-三大特性:封装,继承,多态

封装 继承 # class Animal: # pass # # class xxx: # pass # # class Dog(Animal,xxx): # pass # # # d Dog() # print(d.__class__) # print(Dog.__class__) # # # print(Dog.__bases__) # print(Animal.__bases__) # # object# ---------------------继承-资源…

最小环计数

Problem - 7322 思路&#xff1a;跑一个floyd&#xff0c;同时求出最小环以及进行最小环计数&#xff0c;对于每个环&#xff0c;我们每次用编号最大的点进行统计&#xff0c;防止重复 以下是模板 for(int k1;k<n;k) {for(int i1;i<n;i) {for(int j1;j<n;j) {if(dis…

java快速生成数据库表文档(HTML、DOC、MD)

在企业级开发中、我们经常会有编写数据库表结构文档的时间付出&#xff0c;关于数据库表结构文档状态&#xff1a;要么没有、要么有、但都是手写、后期运维开发&#xff0c;需要手动进行维护到文档中&#xff0c;很是繁琐&#xff0c;这里推荐一个开源项目&#xff1a;screw gi…

读数据压缩入门笔记09_多媒体数据压缩

1. 压缩分类 1.1. 多媒体数据压缩&#xff08;media-specific compression&#xff09; 1.2. 通用压缩&#xff08;general purpose compression&#xff09; 2. 有损压缩算法 2.1. 为了使数据压缩得更小&#xff0c;可以牺牲多媒体的质量这样的数据转换 2.2. 针对特定的多…

Kaggle灾难推文的自然语言处理-最佳得分详解

目录 灾难推文的自然语言处理——预测哪些推文是关于真实灾难的&#xff0c;哪些不是。 一、比赛概述 二、数据集 三、代码 0.导入库与数据 1. 关键字和位置 1.1 缺失值 1.2 元素和目标分布 2. 元特征 3. 目标和N-grams 3.1 目标 3.2 unigrams 一元语法 3.3 big…

[回馈]ASP.NET Core MVC开发实战之商城系统(三)

经过一段时间的准备&#xff0c;新的一期【ASP.NET Core MVC开发实战之商城系统】已经开始&#xff0c;在之前的文章中&#xff0c;讲解了商城系统的整体功能设计&#xff0c;页面布局设计&#xff0c;环境搭建&#xff0c;系统配置&#xff0c;及首页【商品类型&#xff0c;ba…

如何使用ArcGIS Pro制作越来越真实的水域效果

制图的目的就是为了让图更加的美观&#xff0c;这里我们以水域效果为例&#xff0c;为大家讲解一下如何一步步制作越来越真实的水域效果&#xff0c;希望能对你有所帮助。 常规效果 使用过ArcMap制图的朋友应该比较熟悉&#xff0c;可以在符号系统内修改一下填充颜色&#xff…

启用、禁用员工账号

接口相关信息 controller层 /** 启用禁用员工账号* */PostMapping("/status/{status}")ApiOperation("启用禁用员工账号")public Result startOrStop(PathVariable Integer status, Long id) {log.info("启用禁用员工{}&#xff0c;{}",status,i…

Bert模型及变体

ALBert ALBERT就是为了解决模型参数量大以及训练时间过长的问题。ALBERT最小的参数只有十几M, 效果要比BERT低1-2个点&#xff0c;最大的xxlarge也就200多M。可以看到在模型参数量上减少的还是非常明显的&#xff0c;但是在速度上似乎没有那么明显。最大的问题就是这种方式其实…

Kubernetes 之CNI 网络插件对比

介绍 网络架构是Kubernetes中较为复杂、让很多用户头疼的方面之一。Kubernetes网络模型本身对某些特定的网络功能有一定要求&#xff0c;但在实现方面也具有一定的灵活性。因此&#xff0c;业界已有不少不同的网络方案&#xff0c;来满足特定的环境和要求。 CNI意为容器网络接…

Java是什么?为什么众多编程语言要学习Java?Java有哪些特点?

Java 是近 十几 年来计算机软件发展过程中的传奇&#xff0c;其在众多开发者心中的地位可谓“爱不释手”&#xff0c;与其他一些计算机语言随着时间的流逝影响也逐渐减弱不同&#xff0c;Java 随着时间的推移却依然坚挺。 从首次发布开始&#xff0c;Java 就跃到了 Internet 编…

「开源项目」强大易用的开源建站工具-halo

建站工具halo 基本介绍 Halo 作为一款好用又强大的开源建站工具&#xff0c;配合上不同的模板与插件&#xff0c;可以很好地帮助你构建你心中的理想站点。它可以是你公司的官方网站&#xff0c;可以是你的个人博客&#xff0c;也可以是团队共享的知识库&#xff0c;甚至可以是一…

通过Filebeat进行日志监控

对系统的日志监控&#xff0c;通用做法是使用ELK&#xff08;Elasticsearch、Logstash、Kibana&#xff09;进行监控和搜索日志&#xff0c;这里给出另一种方案&#xff1a;通过Filebeat接收日志到Kafka&#xff0c;监控平台接收Kafka&#xff0c;并通过WebSocket实时展示。 这…

Java枚举类的构造函数

Java枚举类可以定义构造函数 Java枚举类可以定义构造函数&#xff0c;枚举常量后面括号中的参数值就是传递给构造函数的参数。 代码示例&#xff1a; package com.thb;public enum Constant {// 枚举常量后面括号中的参数值就是传递给构造函数的参数值REGISTER((byte)0x01),…

windows版docker部署springcloud项目

材料&#xff1a; 1.windows版docker环境&#xff08;其他版教程可能道理一样但是比如文件后坠名上可能有差异&#xff09; 2.运行好的数据库容器&#xff08;实现教程&#xff09; 3.所有jar包 实现&#xff1a; 最后整好的文件夹结构图&#xff08;原工程文件机密&#xf…

教你一文教你使用自己的域名远程访问内网群晖NAS+6.X【内网穿透】

文章目录 使用自己的域名远程访问内网群晖NAS 6.X【内网穿透】 使用自己的域名远程访问内网群晖NAS 6.X【内网穿透】 在之前的文章中&#xff0c;我们向大家演示了如何使用cpolar&#xff0c;创建一条固定的、能够在公共互联网登录内网群晖NAS的数据隧道。这条隧道已经能够应对…

医学案例|ROC曲线之面积对比

一、案例介绍 为评价CT和CT增强对肝癌的诊断效果&#xff0c;共检查了32例患者&#xff0c;每例患者分别用两种方法检查&#xff0c;由医生盲态按4个等级诊断&#xff0c;最后经手术病理检查确诊其中有16例患有肝癌&#xff0c;评价CT个CT增强对肝癌是有有诊断效果并且试着比较…

cpolar内网穿透工具

文章目录 cpolar内网穿透工具 cpolar内网穿透工具 科学技术的发展日新月异&#xff0c;电子设备在人们的生活中已成为不可或缺的工具&#xff0c;甚至在很多情况下&#xff0c;各类型的电子设备已经成为工作的核心&#xff0c;虽然移动设备越来越小巧&#xff0c;功能也越来越…