数据结构 从代码角度看数据结构算法 - 已完结

这篇博客详细介绍了数据结构的各种算法,包括顺序表、链表、栈、队列、二叉树、图等,并提供了C/C++代码实现。作者强调理解数据结构的重要性,并提醒读者注意C++与C语言在编程时的区别。博客内容覆盖了数据结构的主要部分,适合准备408考试或相关课程的学习者参考。
摘要由CSDN通过智能技术生成

-

 

这篇文章主要是数据结构算法,而不是说明数据结构这里面的内容

我本身也非科班,学习数据结构时确实觉得很抽象,但用代码来看觉得理解了一些,学习数据结构前C语言或C++这两门要有一门,不然可能看不懂,JAVA不清楚,我还没学JAVA

全新版本,会更下去,因为复习到408了,希望考408的当做没看到(开玩笑的,加油一起上岸)

主要参考王道主要代码,以及up freedomじゆう,大部分是学习代码,带*的是我个人编写,可能有BUG,其他的也是手写,不过可能会根据我个人情况全部统一一个格式。

参考用书:《数据结构  C语言版  第2版》严蔚敏

基本会把数据结构全部代码全部整合,C++只会用到引用&,循环体内直接定义,因为C需要指针,比较麻烦,其他都是用C语言

408是允许C和C++(请自己核对是否为真),如果考C语言程序设计这门课程那就不能用&和直接定义(严格点的学校可能不给分),只能用*和循环体外先定义变量,请确认课程是否允许使用C++

个人水平有限,有错误麻烦帮忙指正

printf类函数 判断类条件 主要为了健壮性和可读性,考试不写应该没什么问题(个人观点)

-

 

如何运行文内代码?

1.复制全局变量代码,粘贴到能运行C++的环境(C语言环境需要将引用,取值操作改成指针)

2.复制想要运行的代码,粘贴到能运行C++的环境

3.运行

 

全局变量/宏定义

#include <stdio.h>
#include <stdlib.h>
typedef int ElemType;
typedef int Status;
#define MAXSIZE 10
#define TRUE 1
#define FALSE 0
#define ERROR 0
#define OVERFLOW -2
#define OK 1

顺序表(Sequence List)静态分配 

//顺序表静态分配
typedef struct{
	ElemType data[MAXSIZE];
	int length;
}SqList;

//初始化
void InitList(SqList &L)
{
	for (int i = 0; i < MAXSIZE; i++)
		L.data[i] = 0;
	L.length = 0;
}

//插入
int ListInsert(SqList &L, ElemType i, ElemType e)
{
	if (i < 1 || i > L.length + 1)
		return ERROR;
	if (L.length >= MAXSIZE)
		return ERROR;
	for (int j = L.length; j >= i; j--)
		L.data[j] = L.data[j - 1];
	L.data[i - 1] = e;
	L.length++;
	return OK;
}

//按位删除
int ListDelete(SqList &L, ElemType i, ElemType &e)
{
	if (i < 1 || i > L.length)
		return ERROR;
	e = L.data[i - 1];							//王道这里是按位删除,e值带出
	for (int j = i; j < L.length; j++)
		L.data[j - 1] = L.data[j];
	L.length--;
	return OK;
}

//按值删除*
int ValueDelete(SqList &L, ElemType e)
{
	for (int i = 0; i <= L.length; i++)			//从下标0到L.length 最先找到的就删除
	{
		if (e == L.data[i - 1])                  // 也可用[j+1] = [j] 条件变成length-1
		{                                       
			for (int j = i; j <= L.length; j++)	 
				L.data[j - 1] = L.data[j];
			L.length--;
			printf("The value has been deleted.\n");
			return OK;
		}
	}
	printf("Can not find the value.\n");
	return ERROR;
}

//按位查找(获取元素)
Status GetElem(SqList L, int i)
{
	return L.data[i - 1];
}

//按值查找(查找元素)*
int GetValue(SqList L, ElemType e)
{
	for (int i = 0; i <= L.length; i++)
	{
		if (e == L.data[i - 1])
			return i - 1;
	}
	return ERROR;
}

//遍历*
void PrintList(SqList &L)
{
	for (int i = 0; i < L.length; i++)
	{
		printf("data[%d] = %d\n", i, L.data[i]);
	}
	if (L.length > 0)
		printf("SqList length = %d\n",L.length);
}
//main函数,主要用来调用函数
int main()
{
	SqList L;
	InitList(L);
	PrintList(L);
	ListInsert(L, 1, 2);
	ListInsert(L, 2, 3);
	ListInsert(L, 3, 4);
	PrintList(L);
	int e = -1;
	ListDelete(L, 3, e);
	PrintList(L);
	int x = GetElem(L, 2);				//这里是根据位置,返回值
	printf("L.data[x] = %d\n", x);		//GetElem 值
	ListInsert(L, 3, 5);
	PrintList(L);
	ValueDelete(L, 5);
	PrintList(L);
	ListInsert(L, 3, 5);
	x = GetValue(L, 5);					//根据值,返回第一个搜索位置
	printf("L.data[x] = %d\n", x); 
	return 0;
}

---7,22 2022更新

顺序表(Sequence List)动态分配

        静态分配和动态分配主要在 定义结构体、初始化、增加长度(扩容)有区别

        静态分配类似先固定大小,动态分配类似用多少分配多少

        主要在于理解 malloc() 这个函数意义,链表也会用到

//顺序表动态分配
typedef struct{
	ElemType *data;	
	int max;			//最大容量,这个变量是为了扩容用的
	int length;		
}SeqList;

//初始化
int InitSeqList(SeqList &L)
{
	L.data = (ElemType*)malloc(sizeof(ElemType)*MAXSIZE);  //C++可以用new 这条语句是向内存申请分配空间
	if (!L.data)
		return OVERFLOW;
	L.length = 0;
	L.max = MAXSIZE;
	return OK;
}

//获取元素
Status GetElem(SeqList L, int i)
{
	return L.data[i - 1];
}

//查找元素
int LocateElem(SeqList L, ElemType e)
{
	for (int i = 0; i <= L.length; i++)
	{
		if (e == L.data[i - 1])
			return i - 1;
	}
	return ERROR;
}

//插入
int SeqlInsert(SeqList &L, int i, ElemType e)
{
	if (i < 1 || i > L.length + 1)
		return ERROR;
	if (L.length >= L.max)
		return ERROR;
	for (int j = L.length; j >= i; j--)
		L.data[j] = L.data[j - 1];
	L.data[i - 1] = e;
	L.length++;
	return OK;
}

//按位删除
int SeqlDelete(SeqList &L, ElemType i, ElemType &e)
{
	if (i < 1 || i > L.length)
		return ERROR;
	e = L.data[i - 1];
	for (int j = i; j < L.length; j++)
		L.data[j - 1] = L.data[j];
	L.length--;
	return OK;
}

//遍历*
void PrintList(SeqList &L)
{
	for (int i = 0; i < L.length; i++)
	{
		printf("data[%d] = %d\n", i, L.data[i]);
	}
	if (L.length > 0)
		printf("SeqList length = %d\n", L.length);
}

//增加动态数组的长度
void IncreaseSize(SeqList &L, int len)
{
	ElemType *p = L.data;
	L.data = (ElemType*)malloc((L.max + len)*sizeof(ElemType));
	for (int i = 0; i < L.length; i++)
		L.data[i] = p[i];
	L.max = L.max + len;
	free(p);	//释放内存空间
}

//销毁
int SeqlDestroy(SeqList &L)
{
	if (!L.data)
		return ERROR;
	else{
		free(L.data);
		return OK;
	}
}

int main()
{
	SeqList L;
	InitSeqList(L);
	SeqlInsert(L, 1, 2);
	SeqlInsert(L, 1, 6);
	SeqlInsert(L, 2, 10);
	SeqlInsert(L, 2, 10);
	SeqlInsert(L, 2, 10);
	SeqlInsert(L, 2, 10);
	SeqlInsert(L, 2, 10);
	SeqlInsert(L, 2, 10);
	SeqlInsert(L, 2, 10);
	SeqlInsert(L, 2, 11);
	PrintList(L);
	IncreaseSize(L, 5);
	SeqlInsert(L, 2, 13);
	SeqlInsert(L, 3, 15);
	SeqlInsert(L, 2, 17);
	PrintList(L);
	int e = -1;	
	SeqlDelete(L, 2, e);
	PrintList(L);
	printf("GetElem = %d\n", GetElem(L, 1));
	printf("LocateElem = %d\n", LocateElem(L, 2));
	return 0;
}

---7,23 2022更新

单链表(Single Linked List)

        链表是线性表的重点,默认是带头结点,无头结点的只有一个插入函数,有标注

        其中头插法和尾插法非王道版本,参考的是freedomじゆう,可以对比看看

//单链表
typedef struct LNode{
	ElemType data;
	struct LNode *next;
}LNode, *LinkList;
//LNode *L == LinkList L; 等价
//Lnode *temp = (LNode*)malloc(sizeof(LNode)); 新建结点
//L = NULL;  不带头结点

//初始化带头结点单链表
int InitList(LinkList &L)
{
	L = (LNode*)malloc(sizeof(LNode));
	if (L == NULL)		//内存不足的情况
		return FALSE;
	L->next = NULL;		//头结点指向NULL
	return OK;
}

//按位插入
int ListInsert(LinkList &L, int i, ElemType e)
{
	if (i < 1)
		return FALSE;
	LNode *pre;    // Previous 指针 指向插入前一个结点
	int j = 0;
	pre = L;		//L 头结点
	while (pre != NULL && j < i - 1)	//pre找到了i前一个结点
	{
		pre = pre->next;	//从第一个开始找 找不到就下一个结点
		j++;
	}
	if (pre == NULL)
		return FALSE;
	LNode *s = (LNode*)malloc(sizeof(LNode));	//找到了,新建一个结点
	s->data = e;				//1.先将插入结点赋值
	s->next = pre->next;		//2.将i前一个结点的next指针赋值给插入结点
	pre->next = s;				//3.把i前一个结点指向新建结点
	return OK;
}

//不带头结点插入
int NListInsert(LinkList &L, int i, ElemType e)
{
	if (i < 1)
		return FALSE;
	if (i == 1)
	{	//多加一段判断位置为1的情况 其他没有改变
		LNode *s = (LNode*)malloc(sizeof(LNode));
		s->data = e;
		s->next = L;
		L = s;
		return OK;
	}
	LNode *pre;
	int j = 0;
	pre = L;
	while (pre != NULL && j < i - 1)
	{
		pre = pre->next;
		j++;
	}
	if (pre == NULL)
		return FALSE;
	LNode *s = (LNode*)malloc(sizeof(LNode));
	s->data = e;
	s->next = pre->next;
	pre->next = s;
	return OK;
}

//指定结点尾插
int InsertNextNode(LNode *p, ElemType e)	//需要传入指定结点
{
	if (p == NULL)
		return FALSE;
	LNode *s = (LNode*)malloc(sizeof(LNode));
	if (s == NULL)
		return FALSE;
	s->data = e;
	s->next = p->next;
	p->next = s;
	return OK;
}

//指定结点前插
int InsertPriorNode(LNode *p, ElemType e)
{
	if (p == NULL)
		return FALSE;
	LNode *s = (LNode*)malloc(sizeof(LNode));
	if (s == NULL)
		return FALSE;
	s->next = p->next;	//原先p指向的next s也指向p的next
	p->next = s;		//p->next指向s   p-s-x 现在是这样
	s->data = p->data;	//把原先p的data值给s 
	p->data = e;		//把新赋值给到p 这样原先p的data&next都给到s了 s就是原先的p
	return OK;
}

//头插法建立链表(非王道版)
void HeadCreatList(LinkList L, int n)
{
	printf("Please input %d numbers and Separate with SPACE\n", n);
	for (int i = 0; i < n; i++)
	{	//这里是手动键盘输入数据
		LNode *p = (LNode*)malloc(sizeof(LNode));
		int data;
		scanf("%d", &data);
		p->data = data;
		p->next = L->next;
		L->next = p;
	}
}

//尾插法建立链表(非王道版,王道版是头结点建立包含在里面)
void TailCreatList(LinkList L, int n)
{
	printf("Please input %d numbers and Separate with SPACE\n", n);
	LNode *s, *r;
	r = L;		//定义个指针指向头结点,此时头结点是终端结点
	for (int i = 0; i < n; i++)
	{
		LNode *s = (LNode*)malloc(sizeof(LNode));
		int data;
		scanf("%d", &data);
		s->data = data;
		r->next = s;	//r接纳新节点
		r = s;			//r和s指向同个结点,相当于右移
	}
	r->next = NULL;
}

//删除结点
int ListDelete(LinkList &L, int i, ElemType &e)
{
	if (i < 1)
		return FALSE;
	LNode *pre;
	int j = 0;
	pre = L;
	while (pre != NULL && j < i - 1)
	{
		pre = pre->next;
		j++;
	}
	if (pre == NULL)
		return FALSE;
	if (pre->next == NULL)
		return FALSE;
	LNode *temp = pre->next;	//temp指向被删结点
	e = temp->data;				//返回e值
	pre->next = temp->next;		//被删结点前结点指向被删结点后结点
	free(temp);					//temp释放,原文是p,q指针,看个人习惯描述
	return OK;
}

//按位查找(获取元素)
LNode* GetElem(LinkList L, int i)
{
	if (i < 0)
		return NULL;
	LNode *p;
	int j = 0;
	p = L;
	while (p != NULL && j < i)   //j 循环到 i
	{
		p = p->next;
		j++;
	}
	return p;
}

//按值查找(查找元素)
LNode* LocateElem(LinkList L, ElemType e)
{
	LNode *p = L->next;
	while (p != NULL && p->data != e)
		p = p->next;
	return p;
}

//求表的长度
int Length(LinkList L)
{
	int len = 0;
	LNode *p = L;
	while (p->next != NULL)
	{
		p = p->next;
		len++;
	}
	return len;
}

//销毁链表
int LinkListDestroy(LinkList &L)
{
	if (!L)
		return ERROR;
	LinkList p = L;
	while (p)
	{
		LinkList temp = p;
		p = p->next;
		free(temp);
		temp = NULL;
	}
	L = NULL;
	return OK;
}

//遍历*
void PrintList(LinkList &L)
{
	LNode *p = L->next;
	int i = 1;
	while (p != NULL)
	{
		printf("LNode[%d] = %d\n", i, p->data);
		p = p->next;
		i++;
	}
}

int main()
{
	LinkList L;
	InitList(L);
/*	TailCreatList(L, 5);	创建可以用,这里是为了下面测试其他函数
	PrintList(L);
	HeadCreatList(L, 5);
	PrintList(L);			*/
	ListInsert(L, 1, 2);
	ListInsert(L, 2, 4);
	ListInsert(L, 3, 3);
	ListInsert(L, 2, 5);
	PrintList(L);
	printf("List length = %d\n", Length(L));
	int e = -1;
	ListDelete(L, 2, e);
	PrintList(L);
	LNode* ptr = LocateElem(L, 2);
	printf("List length = %d\n", Length(L));
	InsertNextNode(ptr, 8);			
	PrintList(L);
	return 0;
}

---7,24 2022更新 //这个单链表有点麻烦,后面就没那么快更新

双向链表(Double Linked List)

        双向链表和比单链表多了一个Prior指针,指向前驱结点

//双向链表
typedef struct DNode{
	ElemType data;
	struct DNode *prior, *next;
}DNode, *DLinkList;

//初始化
int InitDLinkList(DLinkList &L)
{
	L = (DNode*)malloc(sizeof(DNode));
	if (L == NULL)
		return FALSE;
	L->prior = NULL;
	L->next = NULL;
	return OK;
}

//空表判断
int IsEmpty(DLinkList L)
{
	if (L->next == NULL)
		return TRUE;
	else
		return FALSE;
}

//双链表插入(p结点后插入s结点)
int InsertNextDNode(DNode *p, DNode *s)
{
	if (p == NULL || s == NULL)
		return FALSE;
	s->next = p->next;	     //可以建立一个新建结点函数 来传s结点
	if (p->next != NULL)
		p->next->prior = s;
	s->prior = p;
	p->next = s;
	return OK;
}

//双链表删除(指定结点)
int DeleteNextDNode(DNode *p)
{
	if (p == NULL)
		return FALSE;
	DNode *temp = p->next;
	if (temp == NULL)
		return FALSE;
	p->next = temp->next;   //这里原文就是这么写的 p->next=q->next'
	if (temp->next != NULL)
		temp->next->prior = p;
	free(temp);
	return OK;
}

//双链表插入(非王道版)
int DListInsert(DLinkList &L, int i, ElemType e)
{
	if (i < 1)					//这里可以加判断i值是否合法
		return FALSE;
	DNode *s = (DNode*)malloc(sizeof(DNode));
	DNode *pre;
	int j = 0;
	pre = L;
	while (pre != NULL && j < i - 1)
	{
		pre = pre->next;
		j++;
	}
	if (pre->next == NULL)		//这一段是自己加的,初始化完只有头结点的情况
	{
		s->data = e;
		s->next = NULL;			//因为是最后一个结点 直接NULL
		s->prior = pre;
		pre->next = s;
	} 
	else
	{
		s->data = e;
		s->next = pre->next;
		s->next->prior = s;
		s->prior = pre;
		pre->next = s;
	}
}

//双链表删除(非王道版)
int DListDelete(DLinkList &L, int i, ElemType &e)
{
	if (i < 1)				
		return FALSE;
	DNode *pre;
	int j = 0;
	pre = L;
	while (pre != NULL && j < i - 1)
	{
		pre = pre->next;
		j++;
	}
	DNode *temp = pre->next;			//这里要求掌握的程度到这里应该可以了
	e = temp->data;						//但是这个算法最后两个结点没办法删除
	pre->next = pre->next->next;		//从考试来看到这里就够了
	pre->next->next->prior = pre;		//实际应用可以再加一个被删结点后一个结点的指针
	free(temp);							//再加一个判断最后一个结点和只剩头结点的情况
	temp = NULL;						//双向链表也不算重点吧,会最关键的操作应该就可以了
}										//王道没给指定位置的加和删算法

//销毁双链表
void DestoryList(DLinkList &L)
{
	while (L->next != NULL)
		DeleteNextDNode(L);
	free(L);
	L = NULL;
}

//遍历*
//前项遍历和后项遍历,按值查找和按位查找,包含头结点和不包含
//这里就写一个后项按位遍历
void PrintNext(DLinkList &L)
{
	DNode* p = L->next;
	int i = 1;
	while (p != NULL)
	{
		printf("DNode[%d] = %d\n", i, p->data);
			p = p->next;		//前项p=p->prior; 按值if(p->data!=e);按位函数加个position i;
		i++;
	}
	printf("\n");
}

int main()
{
	DLinkList L;
	InitDLinkList(L);
	if (IsEmpty)
		printf("DLinkList is empty.\n");
	else
		printf("DLinkList is not empty.\n");
	DListInsert(L, 1, 1);
	PrintNext(L);
	DListInsert(L, 2, 3);
	PrintNext(L);
	DListInsert(L, 2, 4);
	PrintNext(L);
	DListInsert(L, 2, 5);
	PrintNext(L);
	DListInsert(L, 1, 6);
	PrintNext(L);
	int e = -1;
	DListDelete(L, 1, e);
	PrintNext(L);
	return 0;
}

---7,26 2022更新

循环链表(Cricular Linked List)

        循环链表增删查改和非循环链表大体类似

        这里没有写main函数和增删查改

        可以复制想要循环的单链表或双链表代码,改一些变量名称就可以运行了

        静态链表:定义两个变量的结构体数组

//循环单链表
typedef struct LNode{
	ElemType data;
	struct LNode *next;
}LNode, *LinkList;

//初始化
int InitList(LinkList &L)
{
	L = (LNode*)malloc(sizeof(LNode));
	if (L == NULL)
		return FALSE;
	L->next = L;
	return OK;
}

//空表判断
int IsEmpty(LinkList L)
{
	if (L->next == L)
		return TRUE;
	else 
		return ERROR;
}

//表尾判断(结点)
int IsTail(LinkList L, LNode *p)
{
	if (p->next == L)
		return TRUE;
	else
		return FALSE;
}

//循环双链表
typedef struct DNode{
	ElemType data;
	struct DNode *prior, *next;
}DNode, *DLinkList;

//初始化
int InitDLinkList(DLinkList &L)
{
	L = (DNode*)malloc(sizeof(DNode));
	if (L == NULL)
		return FALSE;
	L->prior = L;		//双链表这两个指针域都是指向NULL
	L->next = L;
	return OK;
}

//空表判断
int IsEmpty(DLinkList L)
{
	if (L->next == L)
		return TRUE;
	else 
		return ERROR;
}

//表尾判断(结点)
int IsTail(DLinkList L, DNode *p)
{
	if (p->next == L)
		return TRUE;
	else
		return FALSE;
}

---7,27 2022更新

顺序表合并

        顺序表合并(静态动态分配均可),这里用的是动态分配,非有序合并

        La{7,5,3,11};        Lb{2,6,3};        合并后        La{7,5,3,11,2,6,3};

//顺序表动态分配
typedef struct{
	ElemType *data;
	int max;			
	int length;
}SeqList;

//初始化
int InitSeqList(SeqList &L)
{
	L.data = (ElemType*)malloc(sizeof(ElemType)*MAXSIZE); 
	if (!L.data)
		return OVERFLOW;
	L.length = 0;
	L.max = MAXSIZE;
	return OK;
}

//获取元素
Status GetElem(SeqList L, int i)
{
	return L.data[i - 1];
}

//查找元素
int LocateElem(SeqList L, ElemType e)
{
	for (int i = 0; i <= L.length; i++)
	{
		if (e == L.data[i - 1])
			return i - 1;
	}
	return ERROR;
}

//插入
int SeqlInsert(SeqList &L, int i, ElemType e)
{
	if (i < 1 || i > L.length + 1)
		return ERROR;
	if (L.length >= L.max)
		return ERROR;
	for (int j = L.length; j >= i; j--)
		L.data[j] = L.data[j - 1];
	L.data[i - 1] = e;
	L.length++;
	return OK;
}

//遍历*
void PrintList(SeqList &L)
{
	for (int i = 0; i < L.length; i++)
	{
		printf("data[%d] = %d\n", i, L.data[i]);
	}
	if (L.length > 0)
		printf("SeqList length = %d\n", L.length);
}

//顺序表合并
void MergeList(SeqList &La, SeqList &Lb)
{
	for (int i = 1; i < Lb.length + 1; i++)		//判断条件,在Lb的个数下循环
	{
		ElemType e;								//定义一个辅助元素
		e = GetElem(Lb, i);						//i位置的data赋值给e
		if (!LocateElem(La, e))					//如果La没有这个元素
			La.data[La.length++] = e;			//那么就把长度+1的data赋值
	}
}
int main()
{
	SeqList La;
	InitSeqList(La);
	SeqlInsert(La, 1, 7);
	SeqlInsert(La, 2, 5);
	SeqlInsert(La, 3, 3);
	SeqlInsert(La, 4, 11);
	PrintList(La);
	LocateElem(La, 2);
	SeqList Lb;
	InitSeqList(Lb);
	SeqlInsert(Lb, 1, 2);
	SeqlInsert(Lb, 2, 6);
	SeqlInsert(Lb, 3, 3);
	PrintList(Lb);
	MergeList(La, Lb);
	PrintList(La);
	return 0;
}

---7, 28 2022更新

有序顺序表合并

        有序表合并可搭配排序算法

        La{3,5,8,11};        Lb{2,6,8,11,15,20};        合并后        Lc{2,3,5,6,8,8,11,11,15,20};

//顺序表动态分配
typedef struct{
	ElemType *data;
	int max;			
	int length;
}SeqList;

//初始化
int InitSeqList(SeqList &L)
{
	L.data = (ElemType*)malloc(sizeof(ElemType)*MAXSIZE); 
	if (!L.data)
		return OVERFLOW;
	L.length = 0;
	L.max = MAXSIZE;
	return OK;
}

//插入
int SeqlInsert(SeqList &L, int i, ElemType e)
{
	if (i < 1 || i > L.length + 1)
		return ERROR;
	if (L.length >= L.max)
		return ERROR;
	for (int j = L.length; j >= i; j--)
		L.data[j] = L.data[j - 1];
	L.data[i - 1] = e;
	L.length++;
	return OK;
}

//遍历*
void PrintList(SeqList &L)
{
	for (int i = 0; i < L.length; i++)
	{
		printf("data[%d] = %d\n", i, L.data[i]);
	}
	if (L.length > 0)
		printf("SeqList length = %d\n", L.length);
}

//有序顺序表合并(排序算法后应用场景)
void MergeSeqList(SeqList &La, SeqList &Lb, SeqList &Lc)
{															
	Lc.length = La.length + Lb.length;						//将A和B的长度加起来给到新表
	ElemType *pa = La.data, *pa_last = pa + La.length - 1;	//指针指向第一个元素和最后一个元素
	ElemType *pb = Lb.data, *pb_last = pb + Lb.length - 1;
	ElemType *pc = Lc.data;									//pc指针指向新表头个地址
	while (pa <= pa_last && pb <= pb_last)					//这个判定条件是地址大小,顺序表是连续空间
	{														
		if (*pa < *pb)										//如果pa(La)内的数值小于pb(Lb)
			*(pc++) = *(pa++);								//把pa(小的那个)赋值给新表pc
		else
			*(pc++) = *(pb++);
	}														//这两个判断也是上面if判断
	while (pa <= pa_last)									//跳出循环必有一个表空了,两个判断
		*(pc++) = *(pa++);									//这里是pa还有值(pb空了),剩下的给pc
	while (pb <= pb_last)
		*(pc++) = *(pb++);
}

int main()
{
	SeqList La;
	InitSeqList(La);
	SeqlInsert(La, 1, 3);
	SeqlInsert(La, 2, 5);
	SeqlInsert(La, 3, 8);
	SeqlInsert(La, 4, 11);
	PrintList(La);
	SeqList Lb;
	InitSeqList(Lb);
	SeqlInsert(Lb, 1, 2);
	SeqlInsert(Lb, 2, 6);
	SeqlInsert(Lb, 3, 8);
	SeqlInsert(Lb, 4, 11);
	SeqlInsert(Lb, 5, 15);
	SeqlInsert(Lb, 6, 20);
	PrintList(Lb);
	SeqList Lc;
	InitSeqList(Lc);
	MergeSeqList(La, Lb, Lc);
	PrintList(Lc);
	return 0;
}

有序链表合并

        La{3,5,8,11};        Lb{2,6,8,11,15,20};        合并后        Lc{2,3,5,6,8,8,11,11,15,20};

//单链表
typedef struct LNode{
	ElemType data;
	struct LNode *next;
}LNode, *LinkList;

//初始化带头结点单链表
int InitList(LinkList &L)
{
	L = (LNode*)malloc(sizeof(LNode));
	if (L == NULL)		//内存不足的情况
		return FALSE;
	L->next = NULL;		//头结点指向NULL
	return OK;
}

//按位插入
int ListInsert(LinkList &L, int i, ElemType e)
{
	if (i < 1)
		return FALSE;
	LNode *pre;    // Previous 指针 指向插入前一个结点
	int j = 0;
	pre = L;		//L 头结点
	while (pre != NULL && j < i - 1)	//pre找到了i前一个结点
	{
		pre = pre->next;	//从第一个开始找 找不到就下一个结点
		j++;
	}
	if (pre == NULL)
		return FALSE;
	LNode *s = (LNode*)malloc(sizeof(LNode));	//找到了,新建一个结点
	s->data = e;				//1.先将插入结点赋值
	s->next = pre->next;		//2.将i前一个结点的next指针赋值给插入结点
	pre->next = s;				//3.把i前一个结点指向新建结点
	return OK;
}

//头插法建立链表(非王道版)
void HeadCreatList(LinkList L, int n)
{
	printf("Please input %d numbers and Separate with SPACE\n", n);
	for (int i = 0; i < n; i++)
	{	//这里是手动键盘输入数据
		LNode *p = (LNode*)malloc(sizeof(LNode));
		int data;
		scanf("%d", &data);
		p->data = data;
		p->next = L->next;
		L->next = p;
	}
}

//尾插法建立链表(非王道版,王道版是头结点建立包含在里面)
void TailCreatList(LinkList L, int n)
{
	printf("Please input %d numbers and Separate with SPACE\n", n);
	LNode *s, *r;
	r = L;		//定义个指针指向头结点,此时头结点是终端结点
	for (int i = 0; i < n; i++)
	{
		LNode *s = (LNode*)malloc(sizeof(LNode));
		int data;
		scanf("%d", &data);
		s->data = data;
		r->next = s;	//r接纳新节点
		r = s;			//r和s指向同个结点,相当于右移
	}
	r->next = NULL;
}

//求表的长度
int Length(LinkList L)
{
	int len = 0;
	LNode *p = L;
	while (p->next != NULL)
	{
		p = p->next;
		len++;
	}
	return len;
}

//遍历*
void PrintList(LinkList &L)
{
	LNode *p = L->next;
	int i = 1;
	while (p != NULL)
	{
		printf("LNode[%d] = %d\n", i, p->data);
		p = p->next;
		i++;
	}
}

//有序链表合并
void MergeLinkList(LinkList &La, LinkList &Lb, LinkList &Lc)
{							//C语言&变成*
	Lc = La;									//新链表指向La,C语言写法 *La = *La;
	LNode *pa = La->next, *pb = Lb->next;		//两个辅助指针指向第一个结点,C语言写法 LNode *pa = *(La)->next;
	LNode *pc = Lc;							
	while (pa && pb)							//当其中一个表还有数值时循环
	{
		if (pa->data < pb->data)				//如果pa(La)内的指小于pb(Lb)
		{										
			pc->next = pa;						//pc指向pa(小的)
			pc = pa;							//pa的地址给到pc
			pa = pa->next;						//pa移到下一个
		}
		else
		{
			pc->next = pb;
			pc = pb;
			pb = pb->next;
		}
	}
	pc->next = pa ? pa : pb;					//其中一个表没有数据了,判断哪个还有,接给pc
	free(Lb);		
	La = Lb = NULL;
}

int main()
{
	LinkList La, Lb, Lc;
	InitList(La);
	InitList(Lb);
	InitList(Lc);
	ListInsert(La, 1, 3);		//可以用头插尾插法建立,手动数值更方便
	ListInsert(La, 2, 5);		//void HeadCreatList(LinkList L, int n)
	ListInsert(La, 3, 8);
	ListInsert(La, 4, 11);
	ListInsert(Lb, 1, 2);
	ListInsert(Lb, 2, 6);
	ListInsert(Lb, 3, 8);
	ListInsert(Lb, 4, 11);
	ListInsert(Lb, 5, 15);
	ListInsert(Lb, 6, 20);
	PrintList(La);
	printf("LaLinkList length = %d\n", Length(La));
	PrintList(Lb);
	printf("LbLinkList length = %d\n", Length(Lb));
	PrintList(Lc);
	printf("LcLinkList length = %d\n", Length(Lc));
	MergeLinkList(La, Lb, Lc);
	PrintList(Lc);
	printf("LcLinkList length = %d\n", Length(Lc));
	return 0;
}

---7,30 2022更新      //昨天忘发了,第二章完结

顺序栈(Sequence Stack)

        栈这个我分了两个版本,王道版和严蔚敏版,区别是王道版top指针指向最上面的元素,而严蔚敏版top指针指向最上面元素的上面一个元素,我更习惯用严蔚敏版

        举个例子,我这里有5个空间,a[0]~a[4],设a[0]、a[1]内均有元素,那么王道版的top指针是指向a[1],而严蔚敏版是指向a[2] 

        这样好理解吧,那么如果我要存a[4]这个元素严蔚敏版能存吗,答案是可以的,只要S.top-S.base != S.stacksize;里面没满就可以存元素

        这两个版本就是定义S.top指针不一样,而这个差异会导致压栈和出栈完全不同,看你习惯用哪个就用哪个,顺序栈我分两个版本,链栈,队列都是严蔚敏版,栈和队列和链表都是重点,会写出完整代码会更好理解栈和队列,但基础还是顺序表和链表,他们都是这两种构成,不过是栈只能后进先出(LIFO/一端),队列只能先进先出(FIFO/一端),双端队列则不受限制

王道版

//顺序栈
typedef struct{
	ElemType data[MAXSIZE];
	int top;
}SqStack;

//初始化
void InitStack(SqStack &S)
{
	S.top = -1;
}

//判断栈空
int IsEmpty(SqStack S)
{
	if (S.top == -1)
		return TRUE;
	else
		return FALSE;
}

//入栈
int Push(SqStack &S, ElemType x)
{
	if (S.top == MAXSIZE - 1)
		return FALSE;
	S.top = S.top + 1;
	S.data[S.top] = x;			
//	S.data[++S.top] = x;
	return OK;
}

//出栈
int Pop(SqStack &S, ElemType &x)
{
	if (S.top == -1)
		return FALSE;
	x = S.data[S.top];
	S.top = S.top - 1;			//S.data[S.top--] = x;
	return TRUE;
}

//读栈顶元素
int GetTop(SqStack S, ElemType &x)
{
	if (S.top == -1)
		return FALSE;
	x = S.data[S.top];
	return x;
}

/*
//共享栈
typedef struct{
ElemType data[MAXSIZE];
int top0;
int top1;
}

//初始化
void InitStack(ShStack &S)
{
S.top0 = -1;
S.top1 = MAXSIZE;
}
//判断栈满条件 top0 + 1 == top1;
*/

//遍历*
void PrintStack(SqStack S)
{
	
	for (int i = 0; i < S.top + 1; i++)
	{
		printf("Stack[%d] = %d\n", i, S.data[i]);
	}
	printf("\n");
}

int main()
{
	SqStack S;
	InitStack(S);
	Push(S, 1);
	Push(S, 2);
	Push(S, 3);
	PrintStack(S);
	ElemType e = 0;
	printf("GetTop = %d\n", GetTop(S, e));
	while (!IsEmpty(S))			//出完所有栈内元素
	{
		ElemType e = -1;
		Pop(S, e);
		printf("Stack[%d] = %d\n", S.top + 1, e);
	}
	return 0;
}

严蔚敏版

//顺序栈
typedef struct{
	ElemType *base;		//栈底指针
	ElemType *top;		//栈顶指针
	int stacksize;
}SqStack;

//初始化
int InitStack(SqStack &S)
{
	S.base = (ElemType*)malloc(sizeof(ElemType)*MAXSIZE);
	if (!S.base)
		exit(OVERFLOW);
	S.top = S.base;
	S.stacksize = MAXSIZE;
	return OK;
}

//入栈
int Push(SqStack &S, ElemType e)
{
	if (S.top - S.base == S.stacksize)
		return ERROR;
	*S.top++ = e;
	return OK;
}

//出栈
int Pop(SqStack &S, ElemType &e)
{
	if (S.top == S.base)
		return ERROR;
	e = *--S.top;
	return OK;
}

//取栈顶元素
ElemType GetTop(SqStack S)
{
	if (S.top != S.base)
		return *(S.top - 1);
}

//判断栈空
int IsEmpty(SqStack &S)
{
	if (S.base == S.top)
		return TRUE;
	else
		return FALSE;
}

//判断栈满
int IsFull(SqStack &S)
{
	if (S.top - S.base == S.stacksize)
		return TRUE;
	else
		return FALSE;
}

//遍历*
void PrintStack(SqStack S)
{
	int *p, *q;
	p = S.base, q = S.top;			//这个是从低到高,也就是从栈底到栈顶
	int i = 0;						//也可以改成栈顶到栈底遍历
	while (p != q)					//q--,i=S.top-1,就从栈顶遍历,看个人
	{
		printf("Stack[%d] = %d\n", i, *p);
		p++, i++;
	}
}

int main()
{
	SqStack S;
	InitStack(S);
	Push(S, 1);
	Push(S, 2);
	Push(S, 3);
	PrintStack(S);
	ElemType e = 0;
	printf("GetTop = %d\n", GetTop(S));
	int *q = S.top - 1;
	while (!IsEmpty(S))			//出完所有栈内元素
	{
		ElemType e = -1;
		Pop(S, e);
		printf("Stack[%d] = %d\n", *q, e);
		q
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值