0
点赞
收藏
分享

微信扫一扫

线性表综合讲解(思想、实现)

芝婵 2022-05-02 阅读 100

目录

一、顺序表

(一)非动态版本

(二)动态版本

二、链表

(一)单链表

(二)双向链表

三、栈

四、队列


线性表中的数据都像是被串起来一样,具有单一线性关系

一、顺序表

思想:在内存中数据连续存储

这就是一块连续存储的数据。

(一)非动态版本

#define MAX_CAPACITY 100  //定义存储上限
#include<stdio.h>
#include<stdlib.h>
typedef struct Sequencechart
{
	int p[MAX_CAPACITY]; //创建一个数组存储数据
	int sz; //表示已存数量
}S;

void Initchart(S*pf)
{
	pf->p[MAX_CAPACITY] = 0; //存储数据初始化为0
	pf->sz = 0; //存储数量为0
}
int checkcapacity(S*pf)
{
	if (pf->sz == MAX_CAPACITY)  //检查是否超过上限
		return 0;
	else
		return 1;
}
void Add(S*pf, int n)
{
	checkcapacity(pf);
	pf->p[pf->sz] = n; //sz可作为下标
	pf->sz++;
}
int Delete(S*pf, int n)
{
	if (!pf->sz) //顺序表为空,返回0
		return 0;
	for (int i = n - 1; i < pf->sz - 1; i++)  //删除某个数据后,要将后面的数向前移动
		pf->p[i] = pf->p[i + 1];
	pf->sz--;
	return 1;
}
int Check(S*pf, int n)
{
	if (!pf->sz)
		return 0;
	for (int i = 0; i < pf->sz; i++)
	{
		if (n == pf->p[i])
		{
			printf("找到了,下标为%d\n", i); //查找某数据是否存在。
		}
	}
	return 1;
}
int Modify(S*pf, int n, int ps) //传入修改数据,下标
{
	if (!pf->sz)
		return 0;
	if (ps > pf->sz)
		return -1;
	pf->p[ps] = n;
	return 1;
}
int main()
{
	S s;
	Initchart(&s);
	for (int i = 0; i < 9; i++)
		Add(&s, i + 1);
	for (int i = 0; i < s.sz; i++)
		printf("%d ", s.p[i]);
	printf("\n");
	Delete(&s, 5);
	for (int i = 0; i < s.sz; i++)
		printf("%d ", s.p[i]);
	printf("\n");
	Modify(&s, 777, 2);
	for (int i = 0; i < s.sz; i++)
		printf("%d ", s.p[i]);
	printf("\n");
	Check(&s, 777);
	return 0;
}

(二)动态版本

注:当初始空间不足以扩增至所需时,realloc会重新选择一块空间并将原数据拷贝过来

#define INITCAPACITY 3 //初始容量
#define ADDNUM 2   //每次扩增的大小
#include<stdio.h>
#include<stdlib.h>
typedef struct Sequencechart
{
    int*p; //用指针指向内存空间
	int capacity; //当前容量大小
	int sz;
}S;

int Initchart(S*pf)
{
	pf->capacity = INITCAPACITY;
	pf->p = malloc(sizeof(int)*(pf->capacity)); //初始开辟空间
	pf->sz = 0;
	return 1;
}
int checkcapacity(S*pf)
{
	if (pf->sz == pf->capacity) //达到当前容量后扩增
	{
		pf->capacity += ADDNUM;
		pf->p= realloc(pf->p, sizeof(int)*pf->capacity); //realloc第一个参数为指向待扩增空间的指针,即地址,第二个为扩增后的大小,为字节数。
	}
	return 1;
}
int Add(S*pf, int n)
{
	checkcapacity(pf);
	pf->p[pf->sz] = n;
	pf->sz++;
	return 1;
}
int Delete(S*pf, int n)
{
	if (!pf->sz)
		return 0;
	for (int i = n - 1; i < pf->sz - 1; i++)
		pf->p[i] = pf->p[i + 1];
	pf->sz--;
	return 1;
}
int Check(S*pf, int n)
{
	if (!pf->sz)
		return 0;
	for (int i = 0; i < pf->sz; i++)
	{
		if (n == pf->p[i])
		{
			printf("找到了,下标为%d\n", i);
		}
	}
	return 1;
}
int Modify(S*pf, int n,int ps)
{
	if (!pf->sz)
		return 0;
	if (ps > pf->sz)
		return -1;
	pf->p[ps] = n;
	return 1;
}
int main()
 {
	S s;
	Initchart(&s);
	for (int i = 0; i < 9; i++)
		Add(&s, i + 1);
	for (int i = 0; i <s.sz; i++)
		printf("%d ", s.p[i]);
	printf("\n");
	Delete(&s, 5);
	for (int i = 0; i < s.sz; i++)
		printf("%d ", s.p[i]);
	printf("\n");
	Modify(&s, 777, 2);
	for (int i = 0; i < s.sz; i++)
		printf("%d ", s.p[i]);
	printf("\n");
	Check(&s, 777);
	free(s.p);
	return 0;
}

 学会了基本的顺序表后就可以写通讯录这样的小程序了。

二、链表

思想:在内存中数据可以不连续存储,用指针寻找下一个或上一个元素

L*SetLinkList(int n) //创建链表
{
	L*head = NULL, *end = NULL;
	for (int i = 0; i < n; i++)
	{
		L*node = (L*)malloc(sizeof(L));
		node->data = i;
		node->next = NULL;
		if (!head)
			head =end= node;
		else
		{
			end->next = node;
			end = node;
		}
	}
	return head;
}

 

void*Headinsert(L*p, int val) //头插数据
{
	L*node = (L*)malloc(sizeof(L));
	node->data = val;
	node->next = p;
	p = node;
}  

L*Reverse(L*p) //翻转链表
{
	L*newhead = NULL, *node = NULL;
	while (p)
	{
		node = p;
		p = p->next;
		node->next = newhead;
		newhead = node;
	}
	return newhead;
}

(一)单链表

#pragma once
#include<stdio.h>
#include<stdlib.h>
typedef struct LinkList
{
	int data;
	struct LinkList*next;
}L;
L*SetLinkList(int n) //创建链表
{
	L*head = NULL, *end = NULL;
	for (int i = 0; i < n; i++)
	{
		L*node = (L*)malloc(sizeof(L));
		node->data = i;
		node->next = NULL;
		if (!head)
			head =end= node;
		else
		{
			end->next = node;
			end = node;
		}
	}
	return head;
}
L*Addnode(L*p, int val, int n)
{
	L*prev = p;
	L*cur = p;
	while (n--)
	{
		prev = cur;
		cur = cur->next;
	}
	L*node = (L*)malloc(sizeof(L));
	node->data = val;
	prev->next = node;
	node->next = cur;
	return p;
}
void*Headinsert(L*p, int val) //头插数据
{
	L*node = (L*)malloc(sizeof(L));
	node->data = val;
	node->next = p;
	p = node;
}  
L*Delete_fdata(L*p, int val)//数据查找
{
	if (p->data == val)
	{
		p = p->next;
		return p;
	}
	L*prev = p;
	L*cur = p;
	while (cur->data != val)
	{
		prev = cur;
		cur = cur->next;
	}
	prev->next = cur->next;
	free(cur);
	cur = NULL;
	return p;
}
L*Delete_index(L*p, int n)//下标查找
{
	if (n == 1)
	{
		p = p->next;
		return p;
	}
	L*prev = p;
	L*cur = p;
	while (n--)
	{
		if (!cur)
		{
			prev->next = NULL;
			return p;
		}
		prev = cur;
		cur = cur->next;
	}
	prev->next = cur->next;
	free(cur);   //开辟的内存空间一定要释放,防止内存泄漏
	cur = NULL;
	return p;

}
int Find_fdata(L*p, int val)//数据查找
{
	L*cur = p;
	int index = 0;
	while (cur->data != val)
	{
		cur = cur->next;
		index++;
	}
	return index;
}
L*Find_index(L*p, int n)//下标查找
{
	L*cur = p;
	while (n--)
	{
		cur = cur->next;
	}
	return cur;
}
L*Modify(L*p, int val, int n)
{
	L*cur = p;
	Find_index(p, n)->data = val;
	return p;
}
L*Reverse(L*p) //翻转链表
{
	L*newhead = NULL, *node = NULL;
	while (p)
	{
		node = p;
		p = p->next;
		node->next = newhead;
		newhead = node;
	}
	return newhead;
}

(二)双向链表

 

在单链表的基础上增加了一个指向前一个数据的指针

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

typedef struct LinkList
{
	int data;
	struct LinkList*prev;
	struct LinkList*next;
}L;
L*SetLinkList(int n)
{
	L*head = NULL, *end = NULL;
	for (int i = 0; i < n; i++)
	{
		L*node = (L*)malloc(sizeof(L));
		node->data = i;
		node->prev = node->next = NULL;
		if (!head)
			head = end = node;
		else
		{
			node->prev = end;  //让prev指针指向上一次的end
			end->next = node;
			end = node;
		}
	}
	return head;
}
L*Search(L*p, int index)
{
	L*cur = p;
	while (index--)
	{
		cur = cur->next;
	}
	return cur;
}
L*Headadd(L*p,int val) //头插节点
{
	L*node = (L*)malloc(sizeof(L));
	node->data = val;
	node->next = p;
	p->prev = node;
	node->prev = NULL;
	return node;
}
void Add(L*p, int index,int val)
{
	L*cur = Search(p, index);
	L*node = (L*)malloc(sizeof(L));
	node->data = val;
	node->next = cur->next;
	cur->next->prev = node;
	cur->next = node;
	node->prev = cur;
}
void Delete(L*p, int index)
{
	L*cur = p;
	while (index--)
	{
		cur = cur->next;
	}
	cur->prev->next = cur->next; //删除时也要注意prev指针
	cur->next->prev = cur->prev;
	free(cur);
    cur=NULL;
}
void Modify(L*p,int val,int index)
{
	L*cur = Search(p, index);
	cur->data = val;
}

双向链表就不用费劲逆序了

三、栈

思想:先入的数据放在栈底,后入的放在栈顶,遵循先入后出,即FILO(first in last out)

 

 

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

#define INITCAPACITY 10  //栈的初始容量

typedef int STD;   //为数据类型起一个别名,代表栈的数据

typedef struct Stack
{
	STD*base; //栈底为指向内存空间的指针
	STD top; //栈顶可代表下标,这里用数组实现栈,当然还有别的方法
	int capacity; //栈的当前容量
}S;

void InitStack(S*pf)
{
	pf->base =(int*)malloc(sizeof(int)*INITCAPACITY); //初始空间
	pf->capacity = INITCAPACITY;
	pf->top = 0;
}
void checkcapacity(S*pf)
{
	assert(pf); //pf为空断言报错,便于查找错误
	if (pf->top == pf->capacity)
	{
		pf->capacity *= 2; //不够增容为原来的两倍
		pf->base =(STD*)realloc(pf->base,pf->capacity*sizeof(int));
	}
}
//入栈
void StackPush(S*pf, int n)
{
	checkcapacity(pf);
	pf->base[pf->top] = n;
	pf->top++;
}
//出栈
void StackPop(S*pf)
{
	assert(pf&&pf->top > 0);
	pf->top--; //不必释放空间,再次赋值即可重新利用
}
//判断是否为空栈
bool StackEmpty(S*pf)
{
	assert(pf);
	if (pf->top == 0)
		return true;
	else
		return false;
}
//释放栈
void StackDestory(S*pf)
{
	assert(pf);
	pf->capacity = pf->top = 0;
	free(pf->base);
	pf->base = NULL;
}
//获取栈顶元素
int StackTop(S*pf)
{
	assert(pf&&pf->top > 0); //栈顶要大于0才有数据
	return pf->base[pf->top - 1];
}
//获取栈内的数据数量
int StackSize(S*pf)
{
	assert(pf);
	return pf->top;
}

四、队列

思想:先入先出,像通过走廊一样

 

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

typedef	int QUD;

typedef struct QueueNode //这里用链表实现队列
{
	struct QueueNode*next;
	QUD data;
}Qnode;
typedef struct Queue
{
	Qnode*head;
	Qnode*tail;
}Queue;
void QueueInit(Queue*p)
{
	assert(p);
	p->head = p->tail = NULL;
}
//入队列
void QueuePush(Queue*p, QUD n)
{
	assert(p);
	Qnode*node = (Qnode*)malloc(sizeof(Qnode));
	node->next = NULL;
	node->data = n;
	if (p->tail == NULL)
	{
		p->head = p->tail = node;
	}
	else
	{
		p->tail->next = node; //用队尾入数据
		p->tail = node;
	}
}
出队列
void QueuePop(Queue*p)
{
	assert(p&&p->head);
	if (p->head->next == NULL) //只有一个节点直接free头
	{
		free(p->head);
		p->head = p->tail = NULL;
	}
	else
	{
		Qnode*temp = p->head->next; //将下一节点设为头并释放原头内存
		free(p->head);
		p->head = temp;
	}
}
//取队头元素
QUD QueueFront(Queue*p)
{
	assert(p&&p->head);
	return p->head->data;
}
QUD QueueBack(Queue*p)
{
	assert(p&&p->head);
	return p->tail->data;
}
//释放队列
void QueueDestory(Queue*p)
{
	assert(p);
	Qnode*cur = p->head;
	while (cur)
	{
		Qnode*temp = cur->next;
		free(cur);
		cur = temp;
	}
	p->head = p->tail = NULL;
}
//判断队列是否为空
bool QueueEmpty(Queue*p)
{
	return p->head == NULL;
}
//获取队列中元素的个数
int QueueSize(Queue*p)
{
	assert(p);
	int size = 0;
	Qnode*cur = p->head;
	while (cur)
	{
		size++;
		cur = cur->next;
	}
	return size;
}

这里都用了最简单的办法实现栈和队列,先把这四种数据结构的逻辑思想搞懂,再去深入了解其用法和不同的实现方式。

举报

相关推荐

0 条评论