数据结构笔记(更新中)


数据结构与算法

本笔记是根据数据结构与算法基础(青岛大学-王卓)https://www.bilibili.com/video/BV1nJ411V7bd 归纳整理

"*"代表相对重要

1.类C语言补充

image-20220312145747934

data(即数组名)和*data存放的是数组首地址

image-20220312145925084

(ElemType*)表示强制类型转换成指针

image-20220312145940701

image-20220312150020693

2.线性表

2.1 顺序表示

image-20220312150036306

2.1.1 顺序表的基本操作

//函数结果状态代码#define TRUE

#DEFINE ture 1

#DEFINE false 0

#define oK 1

#define ERROR0

#define INFEASIBLE -1

#define OVERFLOW -2 

//Status是函数的类型,其值是函数结果状态代码

typedef int status;

typedef char ElemType;


1. 线性表L的初始化
status initlist_sq(sqlist &L){

L.elem=new ElemType[MAXSIZE];

if(!L.elem) exit(OVERFLOW);

L.legth=0;

return ok;

}
2. 线性表L的销毁与清空
void destroylist(sqlist &L){

if(L.elem) delete L.elem; //释放存储地址空间(delete为c++语法)

}

void clearlist(sqlist &L){

L.length=0; 

}
3. L的长度及是否为空
int GetLength(SqList L){

return (L.length);

}

int lsEmpty(SqList L){

if (L.length==0) return 1;

else return o;
4. 顺序表的取值
int GetElem(SqList L,int i,ElemType &e){

if (i<1||i>L.length)

return ERROR;

e=L.elem[i-1];

 return OK;
 }

**2.1.2 顺序表的值查找(顺序查找)

int LocateELem(SqList L ElemType e){

//在线性表L中查找值为e的数据元素,返回其序号(是第几

个元素)

for (i=0;i< L.length;i++)

if (L.elem[i]==e) return i+1;//查找成功,返回序号return 0; 

//查找失败,返回0
}

平均查找长度:

平均时间复杂度:

O(n)

特点:

? 随机存取

**2.1.3 顺序表的插入

插入位置i:1<=i<=n+1

平均查找长度:

平均时间复杂度:

O(n)

**2.1.4 顺序表的删除

插入位置i:1<=i<=n

平均查找长度:

平均时间复杂度:

O(n)

2.1.5 顺序表的总结

2.2 链式表示

2.2.1 概念

1.无头结点表示空表:

2.有头结点表示空表:

3.头结点的好处:

image-20220312151209556

4.特点:

? 顺序存取

2.2.2 单链表

存储结构(类型定义):

typedef struct Lnode{
	ELEMTYPE data;
	struct londe *next;
	}Londe,*Linklist;

*Linklist表示指向这个结构块的指针

定义指针:

Linklist L / Lnode *L

1.基本操作(带头结点)
1.1 单链表的初始化

1.2 单链表是否为空

*1.2 单链表销毁包括头结点

一个辅助指针

*1.3 单链表清空

两个辅助指针

注:

while(L)等价于while(L!=null)

循环条件不能为while(q)

*1.4 单链表长度

一个辅助指针

**2.取值

一个辅助指针

1<=i<=n

while循环里跳出的情况:

p为null(i>j) j=i i<1 (即: j>i)

符合if条件的:

p为null(i>j) 或 i<1 (即: j>i)

注:此代码为伪代码

**3.查找

一个辅助指针

1<=i<=n

返回指针地址

同:
{
p=L->next;
while(p){
if(p->data=a)
return p;
p=p->next;
}
return p;
}

不成熟总结:
while(  ){
for(  )
}
等价于while(  &&  ) 

返回位置序号

平均查找长度:

平均时间复杂度:

O(n)

**4.插入 (之前)

两个辅助指针

1<=i<=n+1

vs对比

平均时间复杂度:

O(n)

注:插入和删除操作的完整过程包括查找操作,查找操作是O(n),而单个插入和删除操作只是移动指针,只是O(1)

**5.删除

两个辅助指针

1<=i<=n

解析:

p=L;j=0;

因为删除首元结点时要用到头结点,所以将L赋给p,而不是将L->next赋给p

while(p->next&&j

①确保 q指向的地址不为null;如果是while(p&&jnext就无意义(会报错)

while(p) p->next:p会指向第n+1个元素(即null)

while(p->next) p->next:p会指向第n个元素

②p指向第i个结点前驱的固定格式:(循环次数不重要,不虚记忆)

p=L;j=0; while条件是j

p=L->next;j=1; while条件是j

p指向第i个结点的固定格式:

p=L;j=0; while条件是j

p=L->next;j=1; while条件是j

③if(!(p->next)||j>i-1) return error: 表示i不在1<=i<=n这个区间范围内,就return

结论:

p指向第i个结点前驱,while条件是j

p指向第i个结点,while条件是j

平均时间复杂度:

O(n)

注:插入和删除操作的完整过程包括查找操作,查找操作是O(n),而单个插入和删除操作只是移动指针,只是O(1)

**6.建立链表

一个辅助指针

6.1头插法

平均时间复杂度:

O(n)

6.2尾插法

两个辅助指针

平均时间复杂度:

O(n)

2.2.3 循环链表

image-20220302193702043

1.循环链表合并

image-20220302194356080

image-20220302194516778

时间复杂度:

O(1)

2.双向链表

image-20220302195208076

image-20220302195443945

1.插入

image-20220302195756412

4.不可以和1.或2.换

2.删除

image-20220302200538679

不需要去找该删除结点的前驱结点

找第i个结点的时间复杂度:O(n)

下面只执行一次:O(n)

2.3 总结

image-20220302201642970

双向循环链表是用空间换时间

image-20220302202107375

image-20220302202128099

image-20220302202246442

image-20220302202441925

结论:

p指向第i个结点前驱,while条件是j

p指向第i个结点,while条件是j

2.4 应用

image-20220303132008890

2.1 顺序image-20220303133005220

image-20220303133559035

2.2 链式

尾插法

image-20220303134847279

image-20220303134827432

image-20220303135113462

空间复杂度:

O(1)

image-20220303141033792

image-20220303143126890

#include
#include
#define LENGTH sizeof(struct node)
//定义一个节点
int len;//全局变量n
typedef struct node
{
	int Coffficient;
	int Exponent;
	struct node* next;
}*Pnode,Node;
//创建一个单链表(尾插法)
Pnode Create_List()
{
	Node * p,* tail, *head;
	int a,b;
	
	head = (Node*)malloc(LENGTH);//原型应为malloc(1*LENGTH),1省略
	tail = head;
	tail->next = NULL;
	printf("请输入结点个数:");
	scanf_s("%d", &len);
	printf("请输入元素,系数= , 指数=:\n");
	for (int i = 0; i < len; i++)
	{
		scanf_s("%d,%d", &a,&b);
			p = (Node*)malloc(LENGTH);
			p->Coffficient=a;
			p->Exponent = b;
			tail->next = p;
			p->next = NULL;
			tail = p;
	}
	return head;//f返回头结点
}
//按指数排序
void Sort_Linklist1(Node* phead) {//冒泡排序
	Node* p = phead->next;
	Node* q;
	int temp1,temp2, i=0;
	for (; i < len-1; i++, p = p->next) {
		for (q = p->next; q!= NULL; q = q->next) {

			if (p->Exponent < q->Exponent) {
				temp1 = p->Exponent;
				p->Exponent = q->Exponent;
				q->Exponent = temp1;
				temp2 = p->Coffficient;
				p->Coffficient = q->Coffficient;
				q->Coffficient = temp2;
			}
		}
	}	
}
//比较函数
int compare(int Exponent1, int Exponent2) {
	if (Exponent1 > Exponent2)
		return 1;
	if (Exponent1Coffficient = a;
	p->Exponent = b;
	p->next = NULL;
	(*temp)->next = p;
	*temp = p;
}
Pnode Add_List(Node* p1, Node* p2) {
	Node* front,*rear;
	p1 = p1->next;//从头结点的下一节点开始遍历
	p2 = p2->next;
	int sum;
	rear = (Node*)malloc(LENGTH);
	front = rear;
	while (p1 && p2) {
		switch (compare(p1->Exponent, p2->Exponent)) {
		case 1:
			Attach(p1->Coffficient, p1->Exponent, &rear);
			p1 = p1->next;
			break;
		case -1:
			Attach(p2->Coffficient, p2->Exponent, &rear);
			p2= p2->next;
			break;
		case 0:
			sum = p1->Coffficient + p2->Coffficient;
			Attach(sum, p2->Exponent, &rear);
			p1 = p1->next;
			p2 = p2->next;
			break;
		}
	}
	for (; p1; p1 = p1->next)//p2为空循环结束后继续遍历p1
		Attach(p1->Coffficient, p1->Exponent, &rear);
	for(;p2;p2=p2->next)//p1为空循环结束后继续遍历p2
		Attach(p2->Coffficient, p2->Exponent, &rear);
	rear->next = NULL;
	return front;
}

//遍历链表
void Print_List(Node* phead)
{
	Node* p = phead->next;//跳过头结点进行遍历
	while (p != NULL)//尾结点为空时终止(尾结点的指针域为空)
	{
		printf("%dX^%d\t", p->Coffficient,p->Exponent);
		p = p->next;
	}printf("\n");
}

int main()
{
	Node* s1,*s2,*s3;
	printf("请先创建链表\n");
	printf("输入Polynomial1");
	s1= Create_List();
	printf("指数从大到小排序后:\n");
	Sort_Linklist1(s1);
	Print_List(s1);
	printf("输入Polynomial2");
	s2= Create_List();
	Sort_Linklist1(s2);
	printf("指数从大到小排序后:\n");
	Print_List(s2);
	s3=Add_List(s1, s2);
	printf("多项式相加后:\n");
	Print_List(s3);
	return 0;
}

3. 栈和队列

3.1 定义及特点

栈:

image-20220308191426540

image-20220308191542003

image-20220308191941404

image-20220308192006690

队:

image-20220308192212321

特点:

栈:后进先出

队列:先进先出

3.2 应用

image-20220308190926819

image-20220308191156542

3.3 栈的表示和实现

1. 数据类型定义

image-20220308194313532

image-20220308200343193

SElemType是指元素类型

2. 顺序栈

image-20220308200125090

image-20220308200233144

1. 初始化

image-20220308201011261

2. 判断是否为空及长度

image-20220308201050014

image-20220308201116553

3. 清空及释放

image-20220308201158888

image-20220308201334722

delete s.base 释放了数组的内存,但指针还是指向这块内存,只是这块内存不能被访问,所有将它们设为null

4. 入栈

image-20220308202017605

5. 出栈

image-20220308202306823

3. 链表

1. 初始化及是否为空

image-20220308203152145

image-20220308203222498

2. 入栈、出栈及取栈顶

image-20220308203634948

image-20220308203753342

image-20220308203913321

**4.递归

见算法:递归

image-20220308204424327

image-20220308204637067

image-20220308204751278

image-20220308204820580

image-20220308205139653

image-20220308205326741

image-20220308205401420

1. 缺点及转化

image-20220308205841278

image-20220308210002178

image-20220308210017408

image-20220308210155906

image-20220308210206177

3.4 队列的表示和实现

1. 数据类型定义

image-20220309151858382

2.顺序队列

image-20220309153326264

front rear是表示指针,但不是指针变量,不是真正的指针

image-20220309154752167

image-20220309154931280

image-20220309160732666

image-20220309161441800

1. 初始化

image-20220309192825194

2.求队列长度

image-20220309193356243

3.入队

image-20220309193623644

4.出栈

image-20220309193749580

5.取队头元素

3. 链队列

image-20220309194413495

image-20220309194529883

1. 初始化

image-20220309194906589

2. 销毁

3. 入队

image-20220309195431055

4.出队

image-20220309195814383

5. 取队头元素