【数据结构初阶】顺序表

各位读者老爷好,又见面了哈!鼠鼠我呀现在基于C语言浅浅介绍一下数据结构初阶中的顺序表,希望对你有所帮助!

目录

1.线性表 

2.顺序表

2.1概念即结构

2.2动态顺序表接口的实现

2.2.1定义顺序表

2.2.2初始化

2.2.3销毁 

2.2.4打印

2.2.5尾插

2.2.6头插 

2.2.7头删

2.2.8尾删 

2.2.9顺序表查找

 2.2.10顺序表在下标pos位置插入数据x

2.2.11 顺序表删除下标pos位置的值

3.顺序表使用 

3.1test.c

3.2SeqList.h

3.SeqList.c

4.小知识累积(与顺序表无关)

4.1数组越界一定会报错吗?

4.2数组的下标为什么不从1开始而要从0开始呢? 

5.ending

额额额,好哈!顺序表是线性表的一种哈!那我们看看下面是线性表!

1.线性表 

线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串...

线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。

咱们下面介绍的顺序表是一种在逻辑上和物理结构上是连续的。

2.顺序表

2.1概念即结构

顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存
储。在数组上完成数据的增删查改。

与数组不同的是,数组可以在不越界的情况下任意位置存储数据,而顺序表要求数据只能从头开始连续存储。

 顺序表一般可以分为:

1.静态顺序表:使用定长数组存储数据

//顺序表的静态存储
#define N 7
#typedef int SLDataType
typedef struct SeqList
{
SLDataType array[N];//定长数组
size_t size;//有效数据的个数
}SeqList;

2.动态顺序表:使用动态开辟的数组存储

//顺序表的动态存储
#typedef int SLDataType
typedef struct SeqList
{
SLDataType*array;//指向动态开辟的数组
size_t size;//有效数据的个数
size_t capicity;//容量空间的大小
}SeqList;

2.2动态顺序表接口的实现

静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空
间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间
大小,所以下面我们实现动态顺序表。

2.2.1定义顺序表
typedef int SLDateType;

typedef struct SeqList
{
	SLDateType* a;
	int size;                                           //有效数据
	int capaticy;                                       //空间容量
}SeqList;

根据上面定义的顺序表,咱们创建一个顺序表s1,并实现该顺序表一系列接口实现。

SeqList s1;//顺序表
2.2.2初始化
void SeqListInit(SeqList* ps)                               //初始化
{
	assert(ps);
	ps->a = NULL;
	ps->capaticy = 0;
	ps->size = 0;
}

咱们使用顺序表之前需要将有效数据size和空间容量capaticy置零,同时不妨将指向动态开辟数组的指针a置为NULL。

ps:这个函数的参数接收的是上面创建的顺序表s1的地址。

question:实现这个初始化函数参数为啥是s1的地址而不是s1呢?

answer:因为形参是实参的一份临时拷贝,形参的改变不会影响实参。就以这个初始化函数为例,如果这个函数参数是"SeqList s2"的话 ,虽然这个函数中将s2的成员a置为NULL、将s2的成员size和capaticy都置为零,但根本影响不了顺序表s1的成员a、size和capaticy。

就是因为这个原因,下面接口的实现都是采用传递s1的地址。

2.2.3销毁 
void SeqListDestroy(SeqList*ps)                              //销毁
{
	assert(ps);
	if (ps->a != NULL)
	{
		ps->a = NULL;
		ps->capaticy = 0;
		ps->size = 0;
	}
}

咱们如果不再使用顺序表的话,因为顺序表的成员a指向动态开辟的数组,所以最好将这块空间free掉,size和capaticy也最好置零。

 ps:这个函数的参数接收的是上面创建的顺序表s1的地址。

2.2.4打印
void SeqListPrint(SeqList* ps)                               //打印
{
	assert(ps);
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->a[i]);
	}
	printf("\n");
}

必要时可以将存储在顺序表的数据打印出来看看,因为有size个数据,所以循环打印size次即可将数据全部打印出来。

 ps:这个函数的参数接收的是上面创建的顺序表s1的地址。

2.2.5尾插
void SLCheckcapacity(SeqList* ps)                        //扩容
{
	assert(ps);
	if (ps->size == ps->capaticy)
	{
		int newcapaticy = (ps->capaticy == 0) ? 4 : 2 * (ps->capaticy);
		SLDateType* tmp = (SLDateType*)realloc(ps->a, sizeof(SLDateType) * newcapaticy);
		if (tmp == NULL)
		{
			perror("calloc fail");
			return;
		}
		ps->a = tmp;
		ps->capaticy = newcapaticy;
	}
}
void SeqListPushBack(SeqList* ps, SLDateType x)               //尾插
{
	assert(ps);
	SLCheckcapacity(ps);
	ps->a[ps->size] = x;
	ps->size += 1;
}

在顺序表的末尾(下标为size处)处插入数据时直接插入,size加一即可。但要考虑顺序表容量空间是否足够,所以要调用扩容函数SLCheckcapacity,扩容函数的实现大致时当顺序表的size和capaticy一样时,调用realloc函数二倍扩容。 

ps:尾插函数的参数接收的是上面创建的顺序表s1的地址。

2.2.6头插 
void SLCheckcapacity(SeqList* ps)                        //扩容
{
	assert(ps);
	if (ps->size == ps->capaticy)
	{
		int newcapaticy = (ps->capaticy == 0) ? 4 : 2 * (ps->capaticy);
		SLDateType* tmp = (SLDateType*)realloc(ps->a, sizeof(SLDateType) * newcapaticy);
		if (tmp == NULL)
		{
			perror("calloc fail");
			return;
		}
		ps->a = tmp;
		ps->capaticy = newcapaticy;
	}
}
void SeqListPushFront(SeqList* ps, SLDateType x)              //头插
{
	assert(ps);
	SLCheckcapacity(ps);
	int end = ps->size - 1;
	while (end >= 0)
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}
	ps->a[0] = x;
	ps->size++;
}

顺序表头部插入数据就是将第二个及以后的数据均后移,在将所需头插数据x插入到顺序表头部,size加一即可,同样要考虑容量问题。

 ps:头插函数的第一个参数接收的是上面创建的顺序表s1的地址,第二个参数是所需头插数据。

2.2.7头删
void SeqListPopFront(SeqList* ps)                             //头删
{
	assert(ps);
	assert(ps->size > 0);
	int begin = 0;
	while (begin<ps->size-1)
	{
		ps->a[begin] = ps->a[begin+1];
		begin++;
	}
	ps->size--;
}

顺序表删除头部数据也很简单,将第二个及以后的数据均向前覆盖,在将size减一即可。但是需要注意的是,如果size为零的话说明没有数据就不要再删了,用assert断言一下就行。

  ps:这个函数的参数接收的是上面创建的顺序表s1的地址。

2.2.8尾删 
void SeqListPopBack(SeqList* ps)                              //尾删
{
	assert(ps);
	assert(ps->size >0);
	ps->size--;
}

顺序表尾部删除数据最简单,直接将size减一就行,但和头删一样,用assert断言一下防止删空了。

  ps:这个函数的参数接收的是上面创建的顺序表s1的地址。

2.2.9顺序表查找
int SeqListFind(SeqList* ps, SLDateType x)                     //顺序表查找
{
	assert(ps);
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		if (x == ps->a[i])
		{
			return i;//找得到返回下标
		}
	}
	return -1;//找不到返回-1
}

我们也许需要在顺序表中查找某个数据,所以遍历这个顺序表的数据即可,找到返回该数据下标,找不到返回-1。

 ps:该函数的第一个参数接收的是上面创建的顺序表s1的地址,第二个参数是所需查找的数据。

 2.2.10顺序表在下标pos位置插入数据x
void SLCheckcapacity(SeqList* ps)                        //扩容
{
	assert(ps);
	if (ps->size == ps->capaticy)
	{
		int newcapaticy = (ps->capaticy == 0) ? 4 : 2 * (ps->capaticy);
		SLDateType* tmp = (SLDateType*)realloc(ps->a, sizeof(SLDateType) * newcapaticy);
		if (tmp == NULL)
		{
			perror("calloc fail");
			return;
		}
		ps->a = tmp;
		ps->capaticy = newcapaticy;
	}
}
void SeqListInsert(SeqList* ps, int pos, SLDateType x)           //顺序表在下标pos位置插入x
{
	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以后的数据都往后挪,在将所需插入的数据x插入到下标pos的位置,在将size加一即可。但有几处细节要注意:1.pos只能在0和size之间(包括0和size), 否则就越界访问了,所以利用assert断言一下;2.防止顺序表容量不足,调用扩容函数。

ps:该函数的第一个参数接收的是上面创建的顺序表s1的地址,第二个参数是插入位置的下标,第三个参数是需插入的数据。

2.2.11 顺序表删除下标pos位置的值
void SeqListErase(SeqList* ps, int pos)    // 顺序表删除下标pos位置的值
{
	assert(ps);
	assert(pos >= 0 && pos< ps->size);
	int begin = pos + 1;
	while (begin <= ps->size - 1)
	{
		ps->a[begin - 1] = ps->a[begin];
		begin++;
	}
	ps->size--;
}

这个接口实现大致就是将下标pos以后的数据均向前覆盖,size减一即可,若需删除最后一个(下标为size-1)数据 ,无需覆盖,直接size减一即可。细节:下标pos只能在0到size之间(包括0),否则会越界访问,利用assert断言。

ps:该函数第一个参数接收的是上面创建的顺序表s1的地址,第二个参数是需删除数据的下标。

3.顺序表使用 

咱们顺序表接口就实现完了。可以写一个接口来对接上面的所以接口,以实现顺序表的增删查改及初始化、销毁、打印等功能。鼠鼠我写了一个,可以参考参考哈:

3.1test.c

#define _CRT_SECURE_NO_WARNINGS
#include"SeqList.h"
void menu()
{
	printf("**********************\n");
	printf("********0.退出********\n");
	printf("****1.头插  2.头删****\n");
	printf("****3.尾插  4.尾删****\n");
	printf("****5.查找  6.打印****\n");
	printf("*7.在下标pos位置插入值\n");
	printf("*8.删除下标pos位置的值\n");
	printf("**********************\n");
}
int main()
{
	SeqList s1;
	SeqListInit(&s1);
	int input;
	do 
	{
		menu();
		printf("请输入你想操作的数字:->");
		scanf("%d", &input);
		if (input == 0)
		{
			SeqListDestroy(&s1);
			printf("\n");
			break;
		}
		else if (input == 1)
		{
			SLDateType x = 0;
			printf("请输入你要插入的值:->");
			scanf("%d", &x);
			SeqListPushFront(&s1, x);
			printf("\n");
		}
		else if (input == 2)
		{
			SeqListPopFront(&s1);
			printf("\n");
		}
		else if (input == 3)
		{
			SLDateType x = 0;
			printf("请输入你要插入的值:->");
			scanf("%d", &x);
			SeqListPushBack(&s1, x);
			printf("\n");
		}
		else if (input == 4)
		{
			SeqListPopBack(&s1);
			printf("\n");
		}
		else if (input == 5)
		{
			SLDateType x = 0;
			printf("请输入你要查找的值:->");
			scanf("%d", &x);
			int flag=SeqListFind(&s1, x);
			if (flag!=-1)
			{
				printf("你要查找的值下标是%d\n", flag);
			}
			else
			{
				printf("找不到!\n");
			}
			printf("\n");
		}
		else if (input == 6)
		{
			SeqListPrint(&s1);
			printf("\n");
		}
		else if (input == 7)
		{
			SLDateType x = 0; int pos = 0;
			printf("请分别输入你要插入的值及插入的下标:->");
			scanf("%d %d", &x, &pos);
			SeqListInsert(&s1,pos,x);
			printf("\n");
		}
		else if (input == 8)
		{
			int pos = 0;
			printf("请输入你要删除值的下标:->");
			scanf("%d", &pos);
			SeqListErase(&s1,pos);
			printf("\n");
		}
		else
		{
			printf("输入错误,请重新输入:->");
		}
	} while (input);
	return 0;
}

3.2SeqList.h

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int SLDateType;

typedef struct SeqList
{
	SLDateType* a;
	int size;                                           //有效数据
	int capaticy;                                       //空间容量
}SeqList;

void SeqListInit(SeqList* ps);                          //初始化

void SeqListDestroy(SeqList* ps);                       //销毁

void SeqListPrint(SeqList* ps);                         //打印

void SeqListPushBack(SeqList* ps, SLDateType x);        //尾插

void SeqListPushFront(SeqList* ps, SLDateType x);       //头插

void SeqListPopFront(SeqList* ps);                      //头删

void SeqListPopBack(SeqList* ps);                       //尾删

int SeqListFind(SeqList* ps, SLDateType x);             //顺序表查找

void SeqListInsert(SeqList* ps, int pos, SLDateType x); // 顺序表在下标pos位置插入x

void SeqListErase(SeqList* ps, int pos);                // 顺序表删除下标pos位置的值

3.SeqList.c

#define _CRT_SECURE_NO_WARNINGS 
#include"SeqList.h"


void SLCheckcapacity(SeqList* ps)                        //扩容
{
	assert(ps);
	if (ps->size == ps->capaticy)
	{
		int newcapaticy = (ps->capaticy == 0) ? 4 : 2 * (ps->capaticy);
		SLDateType* tmp = (SLDateType*)realloc(ps->a, sizeof(SLDateType) * newcapaticy);
		if (tmp == NULL)
		{
			perror("calloc fail");
			return;
		}
		ps->a = tmp;
		ps->capaticy = newcapaticy;
	}
}


void SeqListInit(SeqList* ps)                               //初始化
{
	assert(ps);
	ps->a = NULL;
	ps->capaticy = 0;
	ps->size = 0;
}


void SeqListDestroy(SeqList*ps)                              //销毁
{
	assert(ps);
	if (ps->a != NULL)
	{
		ps->a = NULL;
		ps->capaticy = 0;
		ps->size = 0;
	}
}


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


void SeqListPushBack(SeqList* ps, SLDateType x)               //尾插
{
	assert(ps);
	SLCheckcapacity(ps);
	ps->a[ps->size] = x;
	ps->size += 1;
}


void SeqListPushFront(SeqList* ps, SLDateType x)              //头插
{
	assert(ps);
	SLCheckcapacity(ps);
	int end = ps->size - 1;
	while (end >= 0)
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}
	ps->a[0] = x;
	ps->size++;
}


void SeqListPopFront(SeqList* ps)                             //头删
{
	assert(ps);
	assert(ps->size > 0);
	int begin = 0;
	while (begin<ps->size-1)
	{
		ps->a[begin] = ps->a[begin+1];
		begin++;
	}
	ps->size--;
}


void SeqListPopBack(SeqList* ps)                              //尾删
{
	assert(ps);
	assert(ps->size >0);
	ps->size--;
}


int SeqListFind(SeqList* ps, SLDateType x)                     //顺序表查找
{
	assert(ps);
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		if (x == ps->a[i])
		{
			return i;//找得到返回下标
		}
	}
	return -1;//找不到返回-1
}


void SeqListInsert(SeqList* ps, int pos, SLDateType x)           //顺序表在下标pos位置插入x
{
	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++;
}


void SeqListErase(SeqList* ps, int pos)                          // 顺序表删除下标pos位置的值
{
	assert(ps);
	assert(pos >= 0 && pos< ps->size);
	int begin = pos + 1;
	while (begin <= ps->size - 1)
	{
		ps->a[begin - 1] = ps->a[begin];
		begin++;
	}
	ps->size--;
}

 各位读者老爷可以将这三个文件放到一个工程下玩玩哦!

4.小知识累积(与顺序表无关)

4.1数组越界一定会报错吗?

answer:越界读基本不会报错。越界写可能会报错。越界的检查是一种抽查行为,就像查酒驾一样,比如数组通常会在数组后面设置一些标记位,一旦标记位的 值被更改就会报错,所以一般在数组末尾附近越界写会报错,但越界太远写就基本不报错了(跳过了标记位)。当然不同的编译器对越界的检查不同。这里只是对越界报错的一种认知。

4.2数组的下标为什么不从1开始而要从0开始呢? 

因为通过下标访问数组本质是指针访问,数组下标从0开始是要和指针的设计自恰!

a[i]等价于*(a+i),只有当下标从0开始时,当i=0时,a[0]=*(a+0)才解释得通。

5.ending

鼠鼠我才疏学浅,且时间紧迫,如有不足,恳请斧正,谢谢哈哈哈!

懂我意思吧?

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

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

相关文章

「Qt Widget中文示例指南」如何模拟一个时钟?

Qt 是目前最先进、最完整的跨平台C开发工具。它不仅完全实现了一次编写&#xff0c;所有平台无差别运行&#xff0c;更提供了几乎所有开发过程中需要用到的工具。如今&#xff0c;Qt已被运用于超过70个行业、数千家企业&#xff0c;支持数百万设备及应用。 点击获取Qt Widget组…

敏捷开发是什么?敏捷开发流程是怎么样的?

1. 什么是敏捷开发&#xff1f; 敏捷开发是一种迭代、增量式的软件开发方法&#xff0c;旨在通过灵活、协作和快速响应变化的方式&#xff0c;提高开发团队的效率和产品的质量。相较于传统的瀑布式开发模型&#xff0c;敏捷开发更加注重用户需求的响应和团队协作&#xff0…

【可解释AI】Alibi explain: 解释机器学习模型的算法

Alibi explain: 解释机器学习模型的算法 可解释人工智能简介Alibi特点算法Library设计展望参考资料 今天介绍Alibi Explain&#xff0c;一个开源Python库&#xff0c;用于解释机器学习模型的预测(https://github.com/SeldonIO/alibi)。该库具有最先进的分类和回归模型可解释性算…

基于Qt 多线程(继承自QThread篇)

# 简介 我们写的一个应用程序,应用程序跑起来后一般情况下只有一个线程,但是可能也有特殊情况。比如我们前面章节写的例程都跑起来后只有一个线程,就是程序的主线程。线程内的操作都是顺序执行的。恩,顺序执行?试着想一下,我们的程序顺序执行,假设我们的用户界面点击有某…

从0开始python学习-32.pytest.mark()

目录 1. 用户自定义标记 1.1 注册标记​编辑 1.2 给测试用例打标记​编辑 1.3 运行标记的测试用例 1.4 运行多个标记的测试用例 1.5 运行指定标记以外的所有测试用例 2. 内置标签 2.1 skip &#xff1a;无条件跳过&#xff08;可使用在方法&#xff0c;类&#xff0c;模…

Leetcode154. Find Minimum in Rotated Sorted Array II

旋转数组找最小&#xff0c;这次值可以重复 不妨假设你已经做了上一题&#xff0c;题解 上一题的方法1肯定是用不了了&#xff0c;因为不再能完全分成2个不同的部分 所以我们沿着方法2走 如果 > n u m s [ r ] >nums[r] >nums[r]&#xff0c;我们依然可以找右半边 …

可以为一个servlet定义多个servlet-mapping、或url-pattern

在web描述符文件web.xml文件中&#xff0c;可以为同一个servlet定义多个servlet-mapping&#xff1b;也可以在同一个servlet-mapping中&#xff0c;定义多个url-pattern。也就是说&#xff0c;可以把多个地址&#xff08;相对于上下文路径&#xff09;映射到同一个servlet处理。…

Windows桌面黑屏无法打开软件窗口不显示卡死等解决方案

问题还原 该软件窗口无论如何操作均 无法打开显示的窗口 ,但是 可使用 ALTTab 看到任务视图 目录 问题还原 解决方案 1. 使用 WinR 打开命令窗口 盲输 cmd 2. 盲输 taskkill /f /im explorer.exe 关闭资源管理器 3. 输入 start explorer.exe 启动任务管理器即可恢复正常…

通过Malloc 和 Free 的具体实现 加深对C指针 的理解(笔记)

【彻底搞懂C指针】Malloc 和 Free 的具体实现 https://danluu.com/malloc-tutorial/ 进程间的通信 : ①共享内存 ② 消息传递 &#xff08;内核实现&#xff09; 分配策略 (实现方面) by DUCK sbrk() malocal实现的主要函数 man sbrk 查看 数据结构 一个参考代码 https…

FD-Align论文阅读

FD-Align: Feature Discrimination Alignment for Fine-tuning Pre-Trained Models in Few-Shot Learning&#xff08;NeurIPS 2023&#xff09; 主要工作是针对微调的和之前的prompt tuining&#xff0c;adapter系列对比 Motivation&#xff1a; 通过模型对虚假关联性的鲁棒…

windows系统winget一键安装和使用

winget命令概述 用户可以在 Windows 10 和 Windows 11 计算机上使用 winget 命令行工具来发现、安装、升级、删除和配置应用程序。 此工具是 Windows 程序包管理器服务的客户端接口 在 Windows 沙盒上安装 winget Windows 沙盒提供了一个轻型桌面环境&#xff0c;可以安全地独…

【数字图像处理】RGB 转灰度图

常见的数字图像格式有 RGB, RGBA, YCbCr 等&#xff0c;RGB/RGBA 格式适合存储&#xff0c;而 YCbCr 格式适合图像处理。在数字图像处理中&#xff0c;通常需要将 RGB 格式的图像变换为灰度图&#xff0c;再进行后续的处理&#xff0c;例如边缘检测、锐化等。本文主要介绍数字图…

改进YOLO系列 | YOLOv5/v7 引入反向残差注意力模块 iRMB | 《ICCV 2023 最新论文》

论文地址:https://arxiv.org/abs/2301.01146 代码地址:https://github.com/zhangzjn/EMO 本论文着重于开发现代、高效、轻量级的模型,用于进行密集预测,同时在参数、FLOPs和性能之间进行权衡。倒置残差块(IRB)作为轻量级CNN的基础设施,但在基于注意力的研究中尚未找到对…

计算机毕业设计选题推荐-个人记账理财微信小程序/安卓APP-项目实战

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…

Linux——vim简介、配置方案(附带超美观的配置方案)、常用模式的基本操作

vim简介、配置方案、常用模式的基本操作 本章思维导图&#xff1a; 注&#xff1a;本章思维导图对应的xmind和.png文件都已同步导入至资源 1. vim简介 vim是Linux常用的文本编辑器&#xff0c;每个Linux账户都独有一个vim编辑器 本篇我们介绍vim最常用的三种模式&#xff1a;…

6可靠的局域网组建

前面聊的拓扑结构都比较简单&#xff0c;所以能用&#xff0c;但是未必可靠。为了可靠&#xff0c;我们需要做冗余&#xff0c;同时需要做一些其他的配置。 生成树协议STP 假设交换机按照上面的方案连&#xff0c;虽然可以提高网络可靠性&#xff0c;但是因为形成了环路&#…

谈谈越来越无效的拥塞控制

简单看一个图&#xff1a; 它不是互联网本身&#xff0c;但这是典型网络的必要组件&#xff0c;它决定了 flow 如何从从一边流向另一边&#xff1a;一条 flow 经过交换节点通过 NIC 被导入一条链路前在 buffer 中排队。 现如今大多数工程师的工作都在折腾那个单独的盒子&…

Django(复习篇)

项目创建 1. 虚拟环境 python -m venv my_env ​ cd my_env activate/deactivate ​ pip install django ​2. 项目和app创建 cd mypros django-admin startproject Pro1 django-admin startapp app1 ​3. settings配置INSTALLED_APPS【app1"】TEMPLATES【 DIRS: [os.pat…

双11终极官方战报 凯迪仕智能锁全网全渠道第一 持续领跑智能锁行业

一年一度双11狂欢盛典暂时落下帷幕&#xff0c;作为下半年最大的电商购物节&#xff0c;本次双11电商平台借机推出优惠券、补贴、折扣等促销活动&#xff0c;激发消费者购物热情。其中&#xff0c;智能门锁等智能家居产品更是取得了亮眼的成交。 据悉&#xff0c;凯迪仕智能锁双…

【Linux】 mdir命令使用

mdir 为mtools工具指令&#xff0c;模拟MS-DOS的dir指令&#xff0c;可显示MS-DOS文件系统中的目录内容。 语法 mdir [参数][目录] mdir命令 -Linux手册页 命令选项及作用 执行令 mdir--help 执行命令结果 参数 -a  显示隐藏文件。-f  不显示磁盘所剩余的可用空间。-w…