链表、队列和栈的实现思路(简单易懂!)

链表代码的逻辑思路

记得要自己尝试着敲一遍,不然等于没看!

头插法

数据结构

struct Node
{
	int data;
	struct Node* next; //表示下一节点
};
  1. 创建链表时,申请malloc头节点,并且头节点的next域为空。
//创建链表
struct Node* createList()
{

	//向内存申请空间
	struct Node* headNode = (struct Node*)malloc(sizeof(struct Node));
	//指向空
	headNode->next = NULL;
	return headNode;
}
  1. 创建结点时,需要传入数据,由于只是单纯的创建结点,其指针域直接指向Null
//创建结点(要插入数据)
struct Node* createNode(int data)
{
	struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
	//插入数据
	newNode->data =data;
	//注意,不是插入结点,是创建结点,所以指向空
	newNode->next = NULL;

	return newNode;
}
  1. 然后是打印链表中的值,只需要使用while循环将结点打印后,移动到下一节点即可。
//打印结点
void printList(struct Node* headNode) {

	//头节点默认不打印,所以直接指向下一个结点
	struct Node* pMove = headNode->next;

	while (pMove)
	{
		printf("%d", pMove->data);

		//移动下一个结点
		pMove = pMove->next;
	}
	printf("\n");
}
  1. 插入一个新节点,首先要传入链表以及数据,然后插入方法中调用创建结点方法,然后将得到的新节点插入链表中,注意:这里使用的是头插法,所以先让新节点指针指向头节点的next域,再让头节点的next指针指向新节点,这里的顺序不能颠倒
//插入结点(头插法)
void insertNode(struct Node* headNode, int data) {

	//创建要插入的结点
	struct Node* newNode = createNode(data);

	//首先让新节点的next指针 指向头节点的下一个结点
	newNode->next = headNode->next;
	//然后再让头节点的next指针指向新节点
	headNode->next = newNode;
}
  1. 删除结点方法,首先是传入链表以及传入的目标结点,由于链表删除是需要两个结点的,所以要声明两个结点,分为:当前结点和当前结点的前一个结点,删除的方法很简单,即将前一个结点的指针跳跃式跳过目标删除结点指向下一个即可。
//删除指定结点
void deleteNode(struct Node* headNode,int posData){

	//目标结点指向头节点的下一个位置
	struct Node* posNode = headNode->next;
	//充当目标结点的前一个位置
	struct Node* posNodeFront = headNode;

	if (posNode==NULL)
	{
		printf("无法删除链表,链表为空\n");
	}
	else {
		//循环匹配找到目标结点
		while (posNode->data!=posData)
		{
			//下面两行的代码表示的是移动位置。
			posNodeFront = posNode;
			//移动到下一个位置
			posNode = posNode->next;

		}
		//如果循环找到了目标结点,则让前一个结点指向目标删除结点的后一个结点
		posNodeFront->next = posNode->next;
		//删除结点
		free(posNode);
	}
}

队列的代码逻辑思路

循环队列

循环队列是用于解决浪费传统队列所带来的空间浪费问题,所以运用到一种取余操作,使得其位置能重新回到队首。

结构体

#define MaxSize 5 //定义最大值
// 循环队列
struct SqQueue
{
	int data[MaxSize];
	int front, rear;// 队头、队尾指针
};

初始化队列

默认情况下队列为空,则队头、队尾指针指向同一个位置

//初始化队列
//默认情况下队列为空,则队头、队尾指针指向同一个位置
void InitQueue(SqQueue &Q) {
	Q.front = 0;
	Q.rear = 0;
	printf("初始化队列成功!\n");
}

判断是否为空

即判断头指针和尾指针是否在同一个位置。

//判断是否为空
int IsEmpty(SqQueue &Q) {
	if(Q.front==Q.rear){
		return 1;
	}
	else
	{
		return 0;
	}
}

入队操作

用取余的操作来判断队列是否为满,并且空余一个空间来做判断。

//循环队列入队操作
int EnQueue(SqQueue &Q,int x){
	//循环队列在入队时,要判断是否为满
	//由于循环队列的特殊性,所以需要空余一个空间出来,以判断队列为满
	//即rear+1时,位置是否和front一致
	if ((Q.rear+1)%MaxSize==Q.front) {
		printf("队列已满!\n");
		return 0;
	}
	//当前位置存放数据
	Q.data[Q.rear] = x;
	//尾指针位置+1(取余操作)
	Q.rear = (Q.rear + 1) % MaxSize;
	return 1;
}

出队操作

//出队操作(首先判断是否为空)
int DeQueue(SqQueue &Q,int x){
	if(IsEmpty(Q)){
		printf("队列为空!\n");
		return 0;
	}
	else
	{
		x = Q.data[Q.front];
		Q.front = (Q.front + 1) % MaxSize;
		return 1;
	}
}

主函数

int main() {
	SqQueue Q;
	InitQueue(Q);
	EnQueue(Q, 1);
	EnQueue(Q, 2);
	EnQueue(Q, 3);
	EnQueue(Q, 4);
	EnQueue(Q, 5);
	PrintQueue(Q);
}

栈的代码逻辑思路

![[Pasted image 20230918202731.png]]

初始化栈

初始化栈时,top指针默认指向-1,即表示栈为空

//初始化队列
void InitStack(Stack &stack) {
	stack.top = -1;
	printf("初始化成功!\n");
}

入栈Push

入栈时,先将指针上移再赋值

//入栈
int Push(Stack &stack,int x) {
	//判断栈是否满
	if (stack.top==MaxSize-1) {
		printf("栈已满!无法入栈!");
		return 0;
	}
	//入栈
	stack.top++;
	stack.data[stack.top] = x;
	return 1;
}

出栈操作Pop

出栈时,先赋值再出栈

//出栈
int Pop(Stack &stack,int x) {
	//判断栈是否为空
	if (stack.top==-1)
	{
		printf("栈为空!无法出队!");
		return 0;
	}
	x = stack.data[stack.top];
	stack.top--;
	return 1;
}

查看栈顶元素

//查看栈顶元素的值
int GetTop(Stack s,int &x) {
	x = s.data[s.top];

	return 1;
}

主函数

int main() {
	Stack s;
	int x;
	InitStack(s);
	Push(s,1);
	Push(s,2);
	Push(s,3);
	Push(s,4);
	Push(s,5);
	GetTop(s, x);
	printf("%d\n",x);
	Pop(s,x);
	GetTop(s, x);
	printf("%d\n", x);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值