数据结构笔记Data Structure

2023-05-16

文章目录

  • 抽象
    • 行为抽象
    • 数据抽象
  • 数据结构Data Structure
    • 抽象数据类型ADT(Abstract Data Type)
  • 线性结构
      • 多项式存储
      • 多项式加法运算
      • 多项式的表示(相乘和相加)
    • 线性表Linear List
      • 线性表的抽象数据类型描述
      • 线性表的顺序存储实现
      • 线性表的链式存储实现
    • 链表的逆转算法
      • 抽象的链表
      • 单链表的逆转
      • 测试数据(边界测试)
    • 广义表(Generalized List)
    • 多重链表
    • 堆栈
      • 堆栈的抽象数据类型描述
      • 栈的顺序存储实现
      • 一个数组实现两个堆栈
      • 堆栈的链式存储实现
      • 堆栈应用:表达式求值
      • 堆栈的其他应用:
    • 队列
      • 队列的抽象数据类型描述
      • 队列的顺序存储实现
      • 队列的链式存储实现
    • 引子
      • 数据管理的基本的三个操作:查找,插入,删除
        • 查找(Searching)
          • 静态查找
    • 什么是树
      • 树的基本术语
    • 二叉树
      • 定义
      • 二叉树五种基本形态
      • 特殊二叉树
        • 斜二叉树
        • 完美二叉树
        • 完全二叉树
      • 二叉树几个重要性质
      • 二叉树的抽象数据类型定义
      • 常用遍历方法:
      • 代码表示
      • 二叉树的存储结构
      • 二叉树的遍历
        • 先序遍历
        • 中序遍历
        • 后序遍历
      • 二叉树的非递归遍历
        • 后序非递归遍历
          • 方法一:
          • 方法二:
      • 层序遍历
      • 二叉树遍历例子
      • 题意理解及二叉树表示
        • 程序框架搭建(判别同构)
      • 二叉搜索树
        • 搜索树特别函数
          • 查找Find
          • 查找最大值和查找最小值
          • 插入
          • 删除
      • 平衡二叉树
        • 平衡二叉树的调整(RR、LL、LR、RL旋转)
      • 判断是否是同一棵二叉搜索树
        • 题意理解
        • 解题方法
        • 求解思路
        • 程序框架搭建
        • 建搜索树
        • 判别
      • 优先队列
      • 堆的特性
      • 堆的抽象数据类型描述
        • 最大堆
          • 创建
          • 插入
          • 删除
          • 应用:堆排序
      • 堆中的路径(例)
    • 哈夫曼树与哈夫曼编码
      • 例引
      • 哈夫曼树定义(最优二叉树)
      • 哈夫曼树构造
      • 哈夫曼树特点
      • 哈夫曼编码
    • 集合
      • 集合的表示
      • 集合运算
      • 集合实例File Transfer(并查集)
      • TSSN实现
      • 按秩归并(对union函数改进)
      • 路径压缩(对find函数改进)
      • 时间复杂度(引理Tarjan)
      • 什么是图
      • 抽象数据类型
      • 常见术语
      • 在程序中表示一个图
        • 邻接矩阵

抽象

行为抽象

  • 通俗地说便是将一个行为序列归并 (抽象)为一个行为的过程

例如: 将 “取碗筷、盛饭、盛菜,扒一口饭、夹一筷菜、再扒一口饭、再夹一筷菜” 的若干重复,然后放下碗筷的过程归并为吃饭。

数据抽象

  • 通俗地说,就是将事物归类,或者说,将事物看成是一定型号、规格的数据,然后将性质接近的数据归纳(抽象)为一类.

例如:将圆、三角形、长方形归为形状类.

数据结构Data Structure

数据结构:

  • 数据对象在计算机中的组织方式
    逻辑结构(线性、树、图)
  • 数据对象必定与一系列加在其上的操作相关联
  • 完成这些操作所用的方法就是算法
  • 一系列性质相同的数据, 组织成一定的逻辑结构, 并带有自身的一系列操作
  • 常见两种存储方式:数组链表

抽象数据类型ADT(Abstract Data Type)

数据类型:

  • 数据对象集
  • 数据集合相关联的操作集

抽象:描述数据类型的方法不依赖于具体实现

  1. 与存放数据的机器无关
  2. 与数据存储的物理结构无关
  3. 与实现操作的算法和编程语言均无关

只描述数据对象集和相关操作集“是什么”,并不涉及“如何做到”的问题

例:“矩阵”的抽象数据类型定义
类型名称:矩阵(Matrix)
数据对象集:一个MxN的矩阵AMxN=(aij)(i=1,…,M;
j=1,…,N)由MxN个三元组<a,i,j>构成,其中a是矩阵元素的值,i是元素所在的行号,j是元素所在的列号。
操作集:对于任意矩阵A、B、C ∈ \in Matrix,以及整数i、j、M、N
Matrix Create(int M, int N):返回一个MxN的空矩阵;
int GetMaxRow(Matrix A):返回矩阵A的总行数;
int GetMaxCol(Matrix A): 返回矩阵A的总列数;
ElementType GetEntry(Matrix A, int i,int j):返回矩阵A的第i行、第j列的元素;
Matrix Add(Matrix A,Matrix B);如果A和B的行、列数一致,则返回矩阵C=A+B,否则返回错误标志;
Matrix Multiply(Matrix A,Matrix B):如果A的列数等于B的行数,则返回矩阵C=AB,否则返回错误标志;

线性结构

多项式存储

方法1:顺序存储结构直接表示

  • 数组各分量对应多项式各项,下标对应项的幂次

a[i]: 项xi的系数ai
在这里插入图片描述

  • 两个多项式相加:两个数组对应分量相加

方法2:顺序存储结构表示非零项(结构数组)

  • 每个非零项aixi涉及两个信息:系数ai和指数i
  • 可以将一个多项式看成是一个(ai,i)二元组的集合
  • 用结构数组表示:数组分类是由系数ai、指数i组成的结构,对应一个非零项

在这里插入图片描述
在这里插入图片描述
方法3:链表结构存储非零项

  • 链表中每个结点存储多项式中的一个非零项,包括系数和指数两个数据域以及一个指针域

在这里插入图片描述
结构表示

typedef struct PolyNode *Polynomial;
struct PolyNode {
	int coef;
	int expon;
	Polynomial link;
};

在这里插入图片描述
在这里插入图片描述

多项式加法运算

采用不带头结点的单向链表,按照指数递减的顺序排列各项
在这里插入图片描述

struct PolyNode {
	int coef; //系数
	int expon; //指数
	struct PolyNode *link; //指向下一个结点的指针
};
typedef struct PolyNode *Polynomial;
Polynomial P1,P2;

算法思路:两个指针P1和P2分别指向这两个多项式第一个结点,不断循环;
P1->expon==P2->expon:系数相加,若结果不为0,则作为结果多项式对应项的系数。同时,P1和P2都分别指向下一项;
P1->expon>P2->expon:将P1的当前项存入结果多项式,并使P1指向下一项;
P1->exponexpon:将P2的当前项存入结果多项式,并使P2指向下一项;
当某一多项式处理完时,将另一个多项式的所有结点依次复制到结果多项式中去。

Polynomial PolyAdd(Polynomial P1, Polynomial P2)
{
	Polynomial front,rear,temp;
	int sum;
	rear=(Polynomial)malloc(sizeof(struct PolyNode));
	front=rear; //由front记录结果多项式链表头结点
	while(P1 && P2) //当两个多项式都有非零项待处理时
	{
		switch(Compare(P1->expon,P2->expon))
		{
			case 1:
				Attach(P1->coef,P1->expon,&rear);
				P1=P1->link;
				break;
			case -1:
				Attach(P2->coef,P2->expon,&rear);
				P2=P2->link;
				break;
			case 0:
				sum=P1->coef + P2->coef;
				if(sum)
				{
					Attach(sum,P1->expon,&rear);
				}
				P1=P1->link;
				P2=P2->link;
				break;
		}
	}
	//将未处理完的另一个多项式的所有结点依次复制到结果多项式中去
	for(;P1;P1=P1->link)
	{
		Attach(P1->coef,P1->expon,&rear);
	}
	for(;P2;P2=P2->link)
	{
		Attach(P2->coef,P2->expon,&rear);
	}
	rear->link=NULL;
	temp=front;
	front=front->link; //令front指向结果多项式第一个非零项
	free(temp); //释放临时空表头结点
	return front;
}

添加函数

void Attach(int c, int e, Polynomial *pRear)
{
	Polynomial P;
	P=(Polynomial)malloc(sizeof(struct PolyNode));
	P->coef=c; //对新节点赋值
	P->expon=e;
	P->link = NULL;
	(*pRear)->link = P;
	*pRear = P; //修改pRear值
}

多项式的表示(相乘和相加)

仅表示非零项
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

struct PolyNode {
	int coef; //系数
	int expon; //指数
	struct PolyNode *link; //指向下一个结点的指针
};
int main()
{
	Polynomial P1,P2,PP,PS;
	P1=ReadPoly();
	P2=ReadPoly();
	PP=Mult(P1,P2);
	PrintPoly(PP);
	PS=Add(P1,P2);
	PrintPoly(PS);
	
	return 0;
}

读入函数

Polynomial ReadPoly()
{
	Polynomial P, Rear,t;
	int c,e,N;
	scanf("%d",&N);
	P=(Polynomial)malloc(sizeof(struct PolyNode)); //链表头空结点
	P->link = NULL;
	Rear = p;
	while(N--)
	{
		scanf("%d %d",&c,&e);
		Attach(c,e,&Rear); //将当前多项式插入尾部
	}
	.t=P;
	P=P->link;
	free(t); //删除临时生成的头结点
	return P;
}
void Attach(int c, int e, Polynomial *pRear)
{
	Polynomial P;
	P=(Polynomial)malloc(sizeof(struct PolyNode));
	P->coef=c; //对新节点赋值
	P->expon=e;
	P->link = NULL;
	(*pRear)->link = P;
	*pRear = P; //修改pRear值
}

在这里插入图片描述
相乘函数(乘法转化为加法)

Polynomial Mult(Polynomial P1, Polynomial P2)
{
	Polynomial P, Rear, t1,t2,t;
	int c,e;
	if(!P1 || !P2)  //由一个多项式为0,返回NULL
	{
		return NULL;
	}
	t1=P1;
	t2=P2;
	P=(Polynomial)malloc(sizeof(struct PolyNode));
	P->link = NULL;
	Rear=P;
	while(t2) //先用P1的第1项乘以P2,得到P
	{
		Attach(t1->coef*t2->coef, t1->expon+t2->expon, &Rear);
		t2=t2->link;
	}
	t1=t1->link;
	while(t1) // 依次用P1余下的项乘以P2的每一项,并及时添加到P中
	{
		t2=P2;
		Rear = P;
		while(t2)
		{
			e=t1->expon + t2->expon;
			c = t1->coef*t2->coef;
			while(Rear->link && Rear->link->expon>e)
			{
				Rear=Rear->link;
			}
			if(Rear->link && Rear->link->expon== e)
			{
				if(Rear->link->coef+c)  //系数相加结果为不为0,更新系数
				{
					Rear->link->coef += c;
				}
				else    //系数相加结果为0,清除该项
				{
					t=Rear->link;
					Rear->link = t->link;
					free(t);
				}
			}
			else
			{
				t=(Polynomial)malloc(sizeof(struct PolyNode));
				t->coef = c;
				t->expon = e;
				t->link = Rear->link;
				Rear->link = t;
				Rear = Rear->link;
			}
			t2=t2->link;
		}
		t1=t1->link;
	}
	t2=P;
	P=P->link;
	free(t2);
	return P;
}

输出函数
void PrintPoly(Polynomial P)
{
int flag = 0; //辅助调整输出格式用
if(!P) //如果P为空,输出0
{
printf(“0 0\n”);
return;
}
while§
{
if(!flag) //第一项不打印空格
{
flag = 1;
}
else
{
printf(" “);
}
printf(”%d %d", P->coef, P->expon);
P=P->link; //移到下一项
}
}

线性表Linear List

多项式表示问题的启示:

  1. 同一个问题可以有不同的表示(存储)方法
  2. 有一类共性问题:有序线性序列的组织和管理

线性表:由同类型数据元素构成有序序列的线性结构

  • 表中元素个数称为线性表的长度
  • 线性表没有元素时,称为空表
  • 表起始位置称表头,表结束位置称表尾

线性表的抽象数据类型描述

  1. 类型名称:线性表(List)
  2. 数据对象集:线性表是n(>=0)个元素构成的有序序列(a1,a2,…,an
  3. 操作集:线性表L∈List,整数i表示位置,元素X∈ElementType,线性表基本操作主要有:

地方

  1. List Make Empty(): 初始化一个空线性表L;
  2. ElementType FindKth(int K, List L): 根据位序K,返回相应元素;
  3. int Find(ElementType X, List L): 在线性表L中查找X的第一次出现位置;
  4. void Insert(ElementType X, int i, List L): 在位序i前插入一个新元素X;
  5. void Delete(int i, List L):删除指定位序i的元素;
  6. int Length(List L): 返回线性表L的长度n。

线性表的顺序存储实现

利用数组的连续存储空间顺序存放线性表的各元素
在这里插入图片描述

typedef struct LNode *List;
struct LNode{
	ElementType Data[MAXSIZE];
	int Last;
};
struct LNode L;
List PtrL;

访问下标为i的元素:L.Data[i]PtrL->Data[i]
线性表的长度:L.Last+1PtrL->Last+1

主要操作实现
1,初始化(建立空的顺序表)

List MakeEmpty()
{
	List PtrL;
	PtrL = (List)malloc(sizeof(struct LNode));
	PtrL->Last = -1;
	return PtrL;
}

2,查找

int Find(ElementType X, List PtrL)
{
	int i=0;
	while(i <= PtrL->Last && PtrL->Data[i] != X)
	{
		i++;
	}
	if(i>PtrL->Last)
	{
		return -1; //如果每找到,返回-1
	}
	else
	{
		return i;   //找到后返回的是存储位置
	}
}

3,插入(第i(1<=i<=n+1)个位置上插入一个值为X的新元素)

  • 先移动再插入
void Insert(ElementType X, int i, List PtrL)
{
	int j;
	if(PtrL->Last == MAXSIZE-1) //表空间已满,不能插入
	{
		printf("表满");
		return;
	}
	if(i<1 || i>PtrL->Last+2) //检查插入位置的合法性
	{
		printf(“位置不合法”);
		return;
	}
	for(j=PtrL->Last; j>=i-1; j--)
	{
		PtrL->Data[j+1] = PtrL->Data[j]; //将数组元素倒序向后移动
	}
	PtrL->Data[i-1] = X; //新元素插入
	PtrL->Last++;  //Last仍指向最后元素
	return;
}

4,删除(删除表的第i(1<=i<=n)个位置上的元素)

  • 后面的元素依次前移
void Delete(int i, List PtrL)
{
	int j;
	if(i<1 || i>Ptrl->Last+1) //检查空表及删除位置的合法性
	{
		printf("不存在第%d个元素",i);
		return;
	}
	for(j=i; j<=PtrL->Last;j++)
	{
		PtrL->Data[j-1] = PtrL->Data[j]; //将a(i+1)~a(n)顺序向前移动
	}
	PtrL->Last--; //Last仍指向最后元素
	return;
}

线性表的链式存储实现

不要求逻辑上相邻的两个元素物理上也相邻;通过“链”建立起数据元素之间的逻辑关系

插入、删除不需要移动数据元素,只需要修改“链”

在这里插入图片描述

typedef struct LNode *List;
struct LNode {
	ElementType Data;
	List Next;
} ;
struct LNode L;
List PtrL;

主要操作实现
1,求表长

int Length(List PtrL)
{
	List p = PtrL; //p指向表的第一个结点
	int j=0;
	while(p)
	{
		p=p->Next;
		j++; //当前p指向的是第j个结点
	}
	return j;
}

2,查找
(1)按序号查找:FindKth;

List FindKth(int K, List PtrL)
{
	List p=PtrL;
	int i=1;
	while(p!=NULL && i<K)
	{
		p=p->Next;
		i++;
	}
	if(i==K)
	{
		return p; //找到第K个,则返回指针
	}
	else
	{
		return NULL//否则返回空
	}
}

(2)按值查找Find

List Find(ElementType X,List PtrL)
{
	List p=PtrL;
	while(p!=NULL && p->Data!= X)
	{
		p=p->Next;
	}
	return p;
}

3,插入(在第i-1(1<=i<=n+1)个结点后插入一个值为X的新结点)
(1)先构造一个新结点,用s指向
(2)再找到链表的第i-1个结点,用p指向;
(3)然后修改指针,插入结点(p之后插入新结点时s)

先让s指向p的下一个结点,然后让p指向s

在这里插入图片描述

List Insert(ElementType X, int i, List PtrL)
{
	List p,s;
	if(i==1)	//新结点插入在表头
	{
		s=(List)malloc(sizeof(struct LNode)); //申请、填装结点
		s->Data=X;
		s->Next=PtrL;
		returns;
	}
	p=FindKth(i-1, PtrL); //查找第i-1个结点
	if(p==NULL)
	{
		printf("参数i错"); //第i-1个不存在,不能插入
		return NULL;
	}
	else
	{
		s=(List)malloc(sizeof(struct LNode)); //申请、填装结点
		s->Data= X;
		s->Next=p->Next; //新结点插入在第i-1个结点的后面
		p->Next=s;
		return PtrL;
	}
}

4,删除(删除链表的第i(1<=i<=n)个位置上的结点)
(1)先找到链表的第i-1个结点,用p指向;
(2)再用指针s指向要被删除的结点(p的下一个结点)s=p->Next;
(3)然后修改指针(s->Next=p->Next),删除s所指结点;
(4)最后释放s所指结点的空间(free(s))。
在这里插入图片描述

List Delete(int i, List PtrL)
{
	List p, s;
	if(i==1) //若要删除的时表的第一个结点
	{
		s=PtrL; //s指向表的第一个结点
		if(PtrL!=NULL)
		{
			PtrL=PtrL->Next; //从链表中删除
		}
		else
		{
			return NULL;
		}
		free(s); //释放被删除结点
		return PtrL;
	}
	p=FindKth(i-1,PtrL); //查找第i-1个结点
	if(p==NULL)
	{
		printf("第%d个结点不存在", i-1);
		return NULL;
	}
	else if(p->Next==NULL)
	{
		printf("第%d个结点不存在", i);
		return NULL;
	}
	else
	{
		s=p->next; //s指向第i个结点
		p->Next=s->Next; //从链表中删除
		free(s); //释放被删除结点
		return PtrL;
	}
}

链表的逆转算法

抽象的链表

在这里插入图片描述

单链表的逆转

在这里插入图片描述
在这里插入图片描述

测试数据(边界测试)

在这里插入图片描述

广义表(Generalized List)

Union的应用
在这里插入图片描述

  • 广义表是线性表的推广;
  • 对于线性表而言,n个元素都是基本的单元素;
  • 广义表中,这些元素不仅可以是单元素也可以是另一个广义表。
typedef struct GNode *GList;
struct GNode {
	int Tag;  //标志域:0表示结点时单元素,1表示结点时广义表
	union {  //子表指针域Sublist与单元素数据域Data复用,即共用存储空间
		ElementType Data;
		GList SubList;
	} URegion;
	GList Next; //指向后继结点
};

在这里插入图片描述
在这里插入图片描述

多重链表

链表中的结点可能同时隶属于多个链

  • 多重链表中结点的指针域会有多个,如前面例子包含了Next和SubList两个指针域;
  • 但包含两个指针域的链表并不一定时多重链表,比如双向链表不是多重链表。

多重链表有广泛的用途:
基本上如树、图这样相对复杂的数据结构都可以采用多重链表方式实现存储
在这里插入图片描述
矩阵A的多重链表图
在这里插入图片描述

堆栈

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

堆栈的抽象数据类型描述

堆栈(Stack):具有一定操作约束的线性表
只在一端(栈顶,Top)做插入、删除

  • 插入数据:入栈(Push)
  • 删除数据:出栈(Pop)
  • 后入先出:Last In First Out(LIFO)

在这里插入图片描述
在这里插入图片描述

栈的顺序存储实现

  • 栈的顺序存储结构通常由一个一维数组和一个记录栈顶元素位置的变量组成
#define MaxSize <存储数据元素的最大个数>
typedef struct SNode *Stack;
struct SNode {
	ElementType Data[MaxSize];
	int Top;
};

(1)入栈

void Push(Stack PtrS, ElementType item)
{
	if(PtrS->Top==MaxSize-1)
	{
		printf("堆栈满");
		return;
	}
	else
	{
		PtrS->Data[++(PtrS->Top)] = item;
		return;
	}
}

(2)出栈

ElementType Pop(Stack PtrS)
{
	if(PtrS->Top == -1)
	{
		printf("堆栈空");
		return ERROR; //ERROR是ElementType的特殊值,标志错误
	}
	else
	{
		return(PtrS->Data[(PtrS->Top)--]);
	}
}

一个数组实现两个堆栈

要求最大地利用数组空间,使数组只要有空间入栈操作就可以成功。

解析:使这两个栈分别从数组的两头开始向中间生长;当两个栈的栈顶指针相遇时,表示两个栈都满了。

#define MaxSize <存储数据元素的最大个数>
struct DStack {
	ElementType Data[MaxSize];
	int Top1; //堆栈1的栈顶指针
	int Top2; //堆栈2的栈顶指针
}S;
S.Top1=-1;
S.Top2=MaxSize;

Push操作

void Push(struct DStack *PtrS, ElementType item, int Tag)
{
	//Tag作为区分两个堆栈的标志,取值为1和2
	if(PtrS->Top2 - PtrS->Top1 == 1) //堆栈满
	{
		printf("堆栈满");
		return;
	}
	if(Tag==1) //对第一个堆栈操作
	{
		PtrS->Data[++(PtrS->Top1)] = item;
	}
	else //对第二个堆栈操作
	{
		PtrS->Data[--(PtrS->Top2)] = item;
	}
}

Pop操作

ElementType Pop(struct DStack *PtrS, int Tag)
{
	//Tag作为区分两个堆栈的标志,取值1和2
	if(Tag==1) //对第一个堆栈操作
	{
		if(PtrS->Top1 == -1) //堆栈1空
		{
			printf("堆栈1空"); 
			return NULL;
		}
		else
		{
			return PtrS->Data[(PtrS->Top1)--];
		}
	}
	else //对第二个堆栈操作
	{
		if(PtrS->Top2 ==MaxSize) //堆栈2空
		{
			printf("堆栈2空");
			return NULL;
		}
		else
		{
			return PtrS->Data[(PtrS->Top2)++];
		}
	}
}

堆栈的链式存储实现

栈的链式存储结构实际上就是一个单链表,叫做链栈。插入和删除操作只能在链栈的栈顶进行。
栈顶指针Top应该在链表的头部

typedef struct SNode *Stack;
struct SNode {
	ElementType Data;
	struct SNode *Next;
};

(1)堆栈初始化(建立空栈)
(2)判断堆栈S是否为空

Stack CreateStack()
{
	//构建一个堆栈的头结点,返回指针
	Stack S;
	S=(Stack)malloc(sizeof(struct SNode));
	S->Next = NULL;
	return S;
}

int IsEmpty(Stack S)
{
	//判断堆栈S是否为空,若为空函数返回整数1,否则返回0
	return (S->Next == NULL);
}

入栈操作

void push(ElementType item, Stack S)
{
	//将元素item压入堆栈
	struct SNode *TmpCell;
	TmpCell=(struct SNode *) malloc(sizeof(struct SNode));
	TmpCell->ElementType = item;
	TmpCell->Next = S->Next;
	S->Next = TmpCell;
}

出栈操作

ElementType Pop(Stack S)
{
	//删除并返回堆栈S的栈顶元素
	struct SNode *FirstCell;
	if(IsEmpty(S))
	{
		printf("堆栈空");
		return NULL;
	}
	else
	{
		FirstCell=S->Next;
		S->Next = FirstCell->Next;
		TopElem = FirstCell->Element;
		free(FirstCell);
		return TopElem;
	}
}

堆栈应用:表达式求值

  • 应用堆栈实现后缀表达式求值的基本过程:
    从左到右读入后缀表达式的各项(运算符或运算数)
    1,运算数:入栈;
    2,运算符:从堆栈中弹出适当数量的运算数,计算并将结果入栈;
    3,最后堆栈顶上的元素就是表达式的结果值

中缀表达式求值

  • 基本策略:将中缀表达式转换为后缀表达式,然后求值
    1,运算数相对顺序不变
    2,运算符号顺序发生改变
    需要存储“等待中”的运算符号
    要将当前运算符号与“等待中”的最后一个运算符号比较
    在这里插入图片描述
    中缀表达式转换为后缀表达式

  • 从头到尾读取中缀表达式的每个对象,对不同对象按不同的情况处理。
    ①运算数:直接输出;
    ②左括号:压入堆栈;
    ③右括号;将栈顶的运算符弹出并输出,直到遇到左括号(出栈,不输出);
    ④运算符:
    优先级大于栈顶运算符时则把它压栈
    优先级小于等于栈顶运算符时,将栈顶运算符弹出并输出;再比较新的栈顶运算符,直到该运算符大于栈顶运算符优先级为止,然后将该运算符压栈
    ⑤若各对象处理完毕,则把堆栈中留存的运算符一并输出

堆栈的其他应用:

  • 函数调用及递归实现
  • 深度优先搜索
  • 回溯算法

队列

队列:具有一定操作约束的线性表
插入和删除操作:只能在一端插入,而在另一端删除
数据插入:入队列(AddQ)
数据删除:出队列(DeleteQ)
先进先出:FIFO

队列的抽象数据类型描述

类型名称:队列(QUEUE)
数据对象集:一个有0个或多个元素的有穷线性表。
操作集:长度为MAXSize的队列Q∈Queue,队列元素item∈ElementType
1、Queue CreatQueue(int MaxSize):生成长度为MaxSize的空队列;
2、int IsFullQ(Queue Q, int MaxSize):判断队列Q是否已满;
3、void AddQ(Queue Q, ElementType item):将数据元素item插入队列Q中;
4、int IsEmptyQ(Queue Q):判断队列Q是否为空;
5、ElementType DeleteQ(Queue Q):将队头数据元素从队列中删除并返回。

队列的顺序存储实现

队列的顺序存储结构通常由一个一维数组和一个记录队头元素位置的变量front以及一个记录队列尾元素位置的变量rear组成。

#define MaxSize <存储数据元素的最大个数>
struct QNode {
	ElementType Data[MaxSize];
	int rear;
	int front;
};
typedef struct QNode *Queue;

顺环队列

  • 问题:
    堆栈空和满的判断条件是什么?
    为什么会出现空、满无法区分?根本原因是什么?
  • 解决方案:
    使用额外标记:Size(0~n)或者tag(0/1)域
    仅使用n-1个数组空间

(1)入队列

void AddQ(Queue PtrQ, ElementType item)
{
	if((PtrQ->rear+1)%MaxSize==PtrQ->front)//求余
	{
		printf("队列满");
		return;
	}
	PtrQ->rear=(PtrQ->rear+1)%MaxSize;
	PtrQ->Data[PtrQ->rear] = item;
}

(2)出队列

ElementType DeleteQ(Queue PtrQ)
{
	if(PtrQ->front==PtrQ->rear)
	{
		printf("队列空");
		return ERROR;
	}
	else
	{
		PtrQ->front=(PtrQ->front+1)%MaxSize;
		return PtrQ->Data[PtrQ->front];
	}
}

队列的链式存储实现

队列的链式存储结构也可以用一个单链表实现。插入和删除操作分别在链表的两头进行;队列指针front指向表头,rear指向表尾

struct Node{
	ElementType Data;
	struct Node *Next;
};
struct QNode { //链队列结构
	struct Node *rear; //指向队尾结点
	struct Node *front; //指向队头结点
};
typedef struct QNode *Queue;
Queue PtrQ;

在这里插入图片描述

  • 不带头结点的链式队列出队操作的一个示例:
ElementType DeleteQ(Queue PtrQ)
{
	struct Node *FrontCell;
	ElementType FrontElem;
	if(PtrQ->front == NULL)
	{
		printf("队列空");
		return ERROR;
	}
	FrontCell = PtrQ->front;
	if(PtrQ->front  == PtrQ->rear) //若队列只有一个元素
	{
		PtrQ->front = PtrQ->rear = NULL; //删除后队列置为空
	}
	else
	{
		PtrQ->front = PtrQ->front->Next;
	}
	FrontElem = FrontCell->Data;
	free(FrontCell); //释放被删除结点空间
	return FrontElem;
}

引子

数据管理的基本的三个操作:查找,插入,删除

查找(Searching)

查找:根据某个给定关键字K,从集合R中找出关键字与K相同的记录

  • 静态查找:集合中记录是固定的
    没有插入和删除操作,只能查找
  • 动态查找:集合中记录时动态变化的
    除查找,还可能发生插入和删除
静态查找
  • 方法1:顺序查找

①哨兵模式:

int SequentialSearch(List Tbl, ElementType K)
{/*在Element[1]~Element[n]中查找关键字为K的数据元素*/
	int i;
	Tbl->Element[0] = K; /*建立哨兵*/
	for(i= Tbl->Length; Tbl->Element[i]!=K; i--)
	{
		;
	}
	return i;/*查找成功返回所在单元下标;不成功返回0*/
}
typedef struct LNode *List;
struct LNode{
	ElementType Element[MAXSIZE];
	int Length;
};

②无哨兵:

int SequentialSearch(List Tbl, ElementType K)
{/*在Element[1]~Element[n]中查找关键字为K的数据元素*/
	int i;
	
	for(i= Tbl->Length; i>0 && Tbl->Element[i]!=K; i--)
	{
		;
	}
	return i;/*查找成功返回所在单元下标;不成功返回0*/
}
  • 方法2:二分查找(Binary Search)

假设n个数据元素的关键字满足有序(比如:小到大)
k1 < k2 < … < kn
并且时连续存放(数组),那么可以进行二分查找。

【例】假设有13个数据元素,按关键字由小到大顺序存放。
二分查找关键字为444的数据元素过程如下:
在这里插入图片描述

int BinarySearch(List Tbl, ElementType K)
{/*在表Tbl中查找关键字为K的数据元素*/
	int left,right,mid,NoFound=-1;
	left=1; //初始左边界
	right = Tbl->Length; //初始右边界
	while(left<=right)
	{
		mid =(left+right)/2; //计算中间元素坐标
		if(K<Tbl->Element[mid])
		{
			right = mid-1; //调整右边界
		}
		else if(K>Tbl->Element[mid])
		{
			left = mid+1; //调整左边界
		}
		else
		{
			return mid; //查找成功,返回数据元素的下标
		}
	}
	return NotFound; //查找不成功,返回-1
}

在这里插入图片描述

什么是树

  • 客观世界中许多事物存在层次关系

人类社会家谱
社会组织结构
图书信息管理

  • 分层次组织在管理上具有更高的效率!

树(Tree):n(n>=0)个结点构成的有限集合。

  • 当n=0时,称为空树;
  • 对于任一棵非空树(n>0),它具备以下性质:
    树中有一个称为“根(Root)”的特殊结点,用r表示;
    其余结点可分为m(m>0)个互不相交的有限集T1,T2,…,Tm,其中每个集合本身又是一棵树,称为原来树的“子树(SubTree)”
  • 子树是不相交的;
  • 除了根结点外,每个结点有且仅有一个父节点
  • 一颗N个结点的树有N-1条边

树的基本术语

1,结点的度(Degree):结点的子树个数
2,树的度:树的所有结点中最大的度数
3,叶结点(Leaf):度为0的结点
4,父结点(Parent):有子树的结点是其子树的根结点的父结点
5,子结点(Child):若A结点时B结点的父结点,则称B结点是A结点的子结点:子结点也称孩子结点
6,兄弟结点(Sibling):具有同一父结点的各结点彼此是兄弟结点
7,路径和路径长度:从结点n1到nk的路径为一个结点序列,ni是ni+1的父结点。路径所包含边的个数为路径的长度。
8,祖先结点(Ancestor):沿树根到某一结点路劲上的所有结点都是这个结点
9,子孙结点(Descendant):某一结点的子树中的所有结点时这个结点的子孙
10,结点的层次(Level):规定根结点在1层,其它任一结点的层数是其父结点的层数加1
11,树的深度(Depth):树中所有结点中的最大层次是这棵树的深度。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二叉树

定义

二叉树T:一个有穷的结点集合

  • 这个集合可以为空
  • 若不为空,则它是由根结点和称为其左子树TL和右子树TR的两个不相交的二叉树组成

二叉树五种基本形态

在这里插入图片描述

特殊二叉树

斜二叉树

在这里插入图片描述

完美二叉树

在这里插入图片描述

完全二叉树

在这里插入图片描述
在这里插入图片描述

二叉树几个重要性质

  • 一个二叉树第i层的最大结点数为:2i-1, i >=1
  • 深度为k的二叉树有最大结点总数为:2k-1, k>=1
  • 对任何非空二叉树T,若n0表示叶结点的个数、n2是度为2的非叶结点个数,那么两者满足关系n0=n2+1

二叉树的抽象数据类型定义

类型名称:二叉树
数据对象集:一个有穷的结点集合。若不为空,则由根结点和其左、右二叉子树组成。
操作集:BT∈BinTree,Item∈ElementType,重要操作有:
1,Boolean IsEmpty(BinTree BT):判别BT是否为空;
2,void Traversal(BinTree BT):遍历,按某顺序访问每个结点;
3,BinTree CreatBinTree():创建一个二叉树。

常用遍历方法:

在这里插入图片描述

代码表示

typedef struct TNode Position;
typedef Position BinTree; /
二叉树类型 /
struct TNode{ /
树结点定义 /
ElementType Data; /
结点数据 /
BinTree Left; /
指向左子树 /
BinTree Right; /
指向右子树 */
};

二叉树的存储结构

1,顺序存储结构
在这里插入图片描述
在这里插入图片描述
2,链表存储
在这里插入图片描述

二叉树的遍历

在这里插入图片描述

先序遍历

在这里插入图片描述

中序遍历

在这里插入图片描述

后序遍历

在这里插入图片描述

二叉树的非递归遍历

在这里插入图片描述
在这里插入图片描述

后序非递归遍历

方法一:
voidPostOrderTraversal(BinTreeBT)
{
	BinTreeT=BT;
	BinTreeExist=NULL;
	StackS=CreatStack(MaxSize);//初始化堆
	while(T||!IsEmpty(S))
	{
		while(T&&T->Left!=Exist&&T->Right!=Exist)
		{
			//是否遍历完,左孩子或右孩子是否已入栈
			Push(S,T);//从(子)树根向左将结点入栈
			T=T->Left;
		}
		if(!IsEmpty(S))
		{
			T=GetTop(S);//获取栈顶元素
			if(T->Right&&T->Right!=Exist)
			{
				//右孩子存在且未入过栈
				T=T->Right;//如果左边最后的结点有右子树,继续上述入栈操作
			}
			else
			{
				T=Pop(S);//没有右子树了,就出栈
				printf("%5d",T->Data);//读根
				Exist=T;//存放已读根的左孩子
				T=GetTop(S);//获取栈顶元素,即返回已读根的父结点
			}
		}
	}
}

难点在于对根的左右孩子是否曾经入过栈的判定,以及栈顶元素的返回时机

方法二:

使用两个栈,s和s2。使用 【根->右->左】 的方式,在第一次遇到结点时,就将结点的值压入栈s2中,那么最后遍历完了,根据栈的性质,s2依次弹出的就是【左->右->根】的后续遍历了

void PostorderTraversal2( BinTree BT ){

    BinTree T = BT;

    stack<BinTree> s;

    stack<ElementType> s2;

    while (T || !s.empty()){

        while (T){

            s.push(T);

            s2.push(T->Data);

            T = T->Right;

        }

        if (!s.empty()){

            T = s.top();

            s.pop();

            T = T->Left;

        }

    }

    while (!sr.empty()){

        printf("%5d", s2.top());

        s2.pop();

    }

}

层序遍历

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

二叉树遍历例子

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

题意理解及二叉树表示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

程序框架搭建(判别同构)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

二叉搜索树

中序遍历是正序的(由小到大排列)

在这里插入图片描述
在这里插入图片描述

搜索树特别函数

在这里插入图片描述

查找Find

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

查找最大值和查找最小值

在这里插入图片描述
在这里插入图片描述

插入

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

删除

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

平衡二叉树

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

平衡二叉树的调整(RR、LL、LR、RL旋转)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

判断是否是同一棵二叉搜索树

题意理解

在这里插入图片描述
在这里插入图片描述

解题方法

在这里插入图片描述
在这里插入图片描述

求解思路

在这里插入图片描述
在这里插入图片描述
flag标记是否被访问过

程序框架搭建

在这里插入图片描述

建搜索树

在这里插入图片描述

判别

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

优先队列

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

堆的特性

在这里插入图片描述
在这里插入图片描述

堆的抽象数据类型描述

最大堆

在这里插入图片描述

创建

在这里插入图片描述

插入

在这里插入图片描述
在这里插入图片描述

删除

在这里插入图片描述
在这里插入图片描述

应用:堆排序

在这里插入图片描述
把最后一个节点和它的父节点(左兄弟)先排序成一个堆,依次往前、往上逐步完成从小堆到大堆的调整。

堆中的路径(例)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

哈夫曼树与哈夫曼编码

例引

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

哈夫曼树定义(最优二叉树)

在这里插入图片描述
在这里插入图片描述

哈夫曼树构造

在这里插入图片描述
在这里插入图片描述

哈夫曼树特点

在这里插入图片描述
在这里插入图片描述

哈夫曼编码

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

集合

集合的表示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

集合运算

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

集合实例File Transfer(并查集)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

TSSN实现

在这里插入图片描述
在这里插入图片描述

按秩归并(对union函数改进)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

路径压缩(对find函数改进)

在这里插入图片描述

时间复杂度(引理Tarjan)

在这里插入图片描述
在这里插入图片描述

什么是图

在这里插入图片描述

抽象数据类型

在这里插入图片描述

常见术语

无向图:所有边不分方向
有向图:边有单向或双向
网络:带权重的图
……

在程序中表示一个图

邻接矩阵

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

数据结构笔记Data Structure 的相关文章

  • 指向结构的指针的大小[重复]

    这个问题在这里已经有答案了 我试图记住 C 编程的基础知识 并且关于结构体指针 我正在执行以下操作 include
  • C :为一个函数参数发送不同的结构

    我有一个使用 OpenGL 绘制圆的函数 我想向它传递一个包含 x 和 y 坐标以及半径的结构 问题是同一个函数必须与 3 个不同的结构一起使用 所有结构都包含坐标 半径和绘图函数不使用的其他一些内容 有没有办法让 3 个不同的结构只有一个
  • 如何按字段之一对结构链接列表进行排序?

    哇现在我知道我不知道 哈哈 我的结构是这样的 struct Medico int Id Doctor int Estado char Nombre 60 focus on this part of the structure this is
  • C4473 结构分配警告

    我目前正在做一项作业 很好奇编译时出现的警告是什么以及如何补救 它会构建 但当我调试时 它会出现错误屏幕 下面是出现的警告 1 gt c 用户 cesteves documents c 编程 库存 库存 inventory cpp 48 警
  • 结构的大小如何随不同数据类型而变化

    我使用的是 Linux 32 位操作系统 和 GCC 编译器 我尝试了三种不同类型的结构 在第一个结构中我只定义了一个char多变的 该结构的大小为 1 这是正确的 在第二个结构中我只定义了一个int多变的 这里结构的大小显示为 4 这也是
  • JavaScript 中的命名空间技术,推荐吗?表现出色?需要注意的问题?

    In a project我正在努力构建我的代码如下 MyLib AField 0 ASubNamespace AnotherField value AClass function param this classField param th
  • 在 C++ 中使用循环创建顺序变量名称

    我正在尝试使用循环创建变量名 具体来说 我正在使用这个结构 struct card string rank string suit 这是我代码的其余部分 其中写着 card i 的地方就是我需要它写 card1 或 card2 等的地方 s
  • XPS 文件的结构是什么

    我认为 XPS 文件就像 PDF 文件 但是 XPS 文件的结构是什么 类似于 PDF 文件吗 CNET 上的 XPS 与 PDF http reviews cnet com 4520 3672 7 6673717 2 html Excer
  • 在 C 和 C# 之间传递包含结构数组的结构(DLL 和 P 调用)

    我有一个带有一些复杂结构的 C dll 我确实是 C 的新手 typedef struct int a int b simple struct typedef struct int d int e simple struct f 20 sh
  • Python argparse 的选项?

    我正在用 Python 编写一个脚本 并使用 argparse 来解析我的参数 该脚本应该比较可用对准器池中的两个不同的 对准器 并且每个对准器都有一些配置选项 我希望能够使用以下方式调用我的脚本 script py aligner ali
  • 访问类中结构的成员

    我有一个 hpp 和 cpp 文件 我想访问类中结构中的变量 该变量恰好位于 cpp 文件的头文件 hpp 中 在 hpp中 我有 class foo public struct packet int x u int y foo const
  • 网站结构

    我对 php 还很陌生 我正在尝试确定组织页面并使用 PHP 交付它们的最佳方式 我的两个 基本 想法是 一堆单独的页面都使用 PHP 包含页眉 页脚和菜单 具有菜单 页眉和页脚以及主要内容的包含的单个主页 页面名称来自 URL 中的变量
  • 带元胞数组的 Matlab 动态字段名结构

    我如何使用动态字段名访问以下结构路径 var refxtree CaseDefinition FlowSheetObjects MaterialStreamObjects 8 MaterialStreamObjectParams Press
  • Java 中的树实现(根、父级和子级)

    我需要创建一个类似于 Java 中所附图像的树结构 我发现了一些与此相关的问题 但我还没有找到令人信服且解释清楚的答复 应用业务包括食品超级品类 主菜 甜品等 每个类别都可以有父项或子项等 import java util ArrayLis
  • c中的嵌套结构

    我必须构建一个嵌套结构来存储有关某人的一些基本信息 姓名 年龄 地址 因此 我创建了一个名为 info 的结构 并为了保存地址 我在 info 内创建了另一个名为 address 的嵌套结构 但每当我提示使用 for 循环存储值时 我都会收
  • 一次更改许多列的值——model.matrix()?

    这是我当前拥有的结构的 dput structure list id c 1 1 2 4 4 country c USA Japan Germany Germany USA USA c 0 0 0 0 0 Germany c 0 0 0 0
  • 二进制 * 的操作数无效(有“ab {aka struct a}”和“ab * {aka struct a *}”)

    我编写了一个程序来交换数组中的两个结构 我的编码如下 include
  • 带有子元素的 Solr 文档?

    是否可以以某种方式创建包含子元素的 solr 文档 例如 我将如何表示这样的事情
  • C++ 中谓词是什么? [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 您能举一些例子或主题链接吗 谓词是一
  • C 相同结构不同尺寸

    我的问题与此相关 c 在struct中定义不同大小的数组 https stackoverflow com questions 17956697 c define arrays in struct with different sizes 但

随机推荐

  • [C++11] 循环引用

    前言 虽然C 43 43 11中的智能指针 xff0c 一定程度上简化了C 43 43 当中的内存管理 xff1b 但是 xff0c shared ptr lt gt 的使用同时也引出了另一个问题 xff1a 循环引用 例子 让我们先来看一
  • MyBatis Plus快速入门

    MyBatis Plus 国产的开源框架 xff0c 基于 MyBatis 核心功能就是简化 MyBatis 的开发 xff0c 提高效率 MyBatis Plus 快速上手 Spring Boot 2 3 0 43 MyBatis Plu
  • jpeg库的移植步骤(GEC6818)

    移植jpeg库 1 将jpegsrc v9a tar gz 解压到共享目录 tar zxvf jpegsrc v9a tar gz C x c z j 压缩GZ xff1a cz 解压bz2格式 xff1a xj C xff1a 指定包解压
  • NSFileManager文件和文件夹的操作

    NSFileManager的文件操作 上面中简单的介绍了数据存储 但是在获取数据 要存储时 一般需要创建一个单独的文件或者文件夹报保存你要存储的数据 所以要介绍一下NSFileManager 这个很重要 在日常开发中会经常使用到这个类 NS
  • 数组排序(C 语言实现)

    本文主要包含常见的数组排序方法 选择排序 原理 在原始数组中取未排序的首元素 xff0c 与其后方所有元素比较 xff0c 不满足顺序 xff0c 则交换首元素此时满足条件 xff0c 未排序部分后移重复上述操作 代码实现 include
  • qt 配置open3d

    一 配置前要先编程open3d 二 开始配置 新建txt 把txt 修改为 pri 在pro 文件中添加 include F xuwanlu control pri 重新构建项目然后回多出来pri 在pri中添加open3d目录 INCLU
  • Python的序列切片

    Python提供了一种把序列切成小块的操作 xff0c 称为切片 xff08 slice xff09 操作 xff0c 其本质是访问由序列中的某些元素所构成的子集 Python的序列数据结构都支持切片操作 xff0c 如列表 元组 字符串等
  • CMFCShellTreeCtrl控件的效率改进

    VS2010新增加 xff08 相较于VC6 xff09 了一个CMFCShellTreeCtrl 类 xff0c 说实话 xff0c 这个类确实很好 xff0c 但是有一点你会发现 xff0c 在展开某些节点的时候可能会很慢很慢 这严重影
  • 利用storyboard 自定义cell

    现在讲究的是快速开发 xff0c storyboa 39 r 39 d自定义cell还是比较少用得 xff0c 但是开发起来特别快 镔哥就不多说了 xff0c 直接给你们demo看吧 1 xff1a 自定义cell xdxTableView
  • gcc命令行详解

    1 gcc包含的c c 43 43 编译器 gcc cc c 43 43 g 43 43 gcc和cc是一样的 xff0c c 43 43 和g 43 43 是一样的 xff0c 没有看太明白前面这半句是什 么意思 一般c 程序 就用gcc
  • 解决远程桌面不能复制粘贴的方法

    1 杀死rdpclip exe进程 2 开始 gt 运行 gt rdpclip exe 重新运行此程序
  • 《计算机应用》期刊投稿经验

    文章目录 投稿经历投稿流程正刊 OR 增刊版面费注意事项常见问题 投稿经历 1 做的区块链方向 2 从做完试验 xff0c 然后开始写论文 xff0c 写了一个月左右 xff0c 然后交给导师改 xff0c 改了一个礼拜 xff0c 之后就
  • mac初次使用php环境简单搭建

    mac电脑默认已经安装apache服务 xff0c apache配置文件路径为 xff1a etc apache2 httpd conf apache服务启动 关闭 重启命令 xff1a sudo apachectl start stop
  • 阿里云缓存服务器里面的一个坑

    今天在做视频同步的时候无意中发现的一个坑 公司的服务器是放在了阿里云上面的 xff0c 阿里云有个十分给力的路由缓存功能 xff0c 就是通过各种cache头去访问服务器的时候 xff0c 阿里云会把这个结果保存到缓存服务器中 xff0c
  • 【树莓派4B学习笔记】无显示屏使用网线配置树莓派系统

    在咸鱼买了个二手树莓派4B 4G xff0c 准备拿来学习Linux的 xff0c 不过目前还是先学习配置官方的系统Raspios xff08 以前叫Raspbian xff09 其实到手的时候卡里有系统 xff0c 但还是想自己动手试试
  • ESP8266工作模式/烧录模式(整合)

    目录 一 硬件部分 1 工作模式 烧录模式 Q amp A xff1a 二 ESP 01 arduino烧写 1 首选项配置 2 https arduino esp8266 com stable package esp8266com ind
  • 以太网与 TCP/IP

    以太网 Ethernet 以太网是一套标准 xff0c 制定了相当于 OSI 模型 中第一层 xff08 物理层 xff09 和第二层 xff08 数据链路程 xff09 的技术规范 在物理层上 xff0c 以太网采用 RJ45 接口和双铰
  • Debian10(xfce4)Linux换源中文输入法sudo等常用软件安装配置

    文章目录 1 debian系统安装选英文还是中文2 安装设置sudo xff08 debian默认是没有的 xff09 xff1a 3 debian10换国内源https测试版testing源稳定版stable源 3 安装网络管理插件与代理
  • 关于ACLLib

    文章目录 ACLLib基本操作 xff1a Dev C 43 43 下创建配置 xff1a 绘图函数 xff1a The Callbacks xff08 回调事件 xff09 MVC设计模式 ACLLib基本操作 xff1a Dev C 4
  • 数据结构笔记Data Structure

    文章目录 抽象行为抽象数据抽象 数据结构Data Structure抽象数据类型ADT xff08 Abstract Data Type xff09 线性结构多项式存储多项式加法运算多项式的表示 xff08 相乘和相加 xff09 线性表L