数据结构例题代码及其讲解-栈与队列

这篇具有很好参考价值的文章主要介绍了数据结构例题代码及其讲解-栈与队列。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

栈与队列

栈Stack

后进先出

​ 栈的结构体定义及基本操作。

#define MaxSize 50
typedef struct {
	int data[MaxSize];//栈中存放数据类型为整型
	int top;//栈顶指针
}Stack;

初始化

​ 这里初始化时是将栈顶指针指向-1,有些则是指向0,因此后续入栈出栈的代码略微有点区别

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

判断栈是否为空

int IsEmpty(Stack S) {//判断栈是否为空
	if (S.top == -1)
		return 1;
	else
		return 0;
}

压栈操作

  1. 由于初始时栈顶指针指向-1,因此需要先变化栈顶指针,然后入栈操作;
  2. 且当MaxSize为50时候,数据域在data[0]~data[49],因此这里是S.top == MaxSize - 1表示栈满;
  3. 第4-5行可以合并为S.data[++S.top]=x。
int Push(Stack& S, int x) {//压栈操作
	if (S.top == MaxSize - 1)//若栈满则无法压栈
		return 0;
	S.top++;
	S.data[S.top] = x;
	return 1;
}

出栈操作

  1. 这里将出栈的元素用x接收,出栈时先接收,然后栈顶指针自减
  2. 第4-5行可以合并为x=S.data[++S.top]
int Pop(Stack& S, int& x) {//出栈操作
	if (S.top == -1)//若栈空则无法出栈
		return 0;
	x = S.data[S.top];
	S.top--;
	return 1;
}

读取栈顶元素

​ 这里将出栈的元素用x接收

int GetTop(Stack S, int& x) {//读取栈顶元素
	if (S.top == -1)//若栈空则无栈顶元素
		return 0;
	x = S.data[S.top];
	return 1;
}

​ 当然以上的是顺序栈,还有链栈,和单链表类似,带头结点处为栈头,另外一边为栈底,入栈出栈都在头结点处进行,方便操作。

01 有一个带头结点的单链表 L,结点结构由 data 和 next 两个域构成,其中data 域为字符型。试设计算法判断该链表的全部 n 个字符是否中心对称。例如xyx、xyyx 都是中心对称。
  1. 判断这类是否中心对称,一般都是用到栈;
  2. 本题中将其分为前后两部分,把前半部分依次入栈,到后半部分时,与出栈元素进行比较,比较完后栈顶指针移动。遍历指针移动;
  3. 易错for循环入栈结束后,i所在的位置在栈顶元素的后一个位置,需要i–将其返回到栈顶位置
  4. 结点个数为偶数时,正常处理,个数为奇数时,最中间元素不将其压栈处理,让遍历指针再走一步,绕过中间元素;
int central_symmetry(LinkList L, int n) {
	char S[n / 2];//定义字符型数组来作为一个栈
	int i;//定义栈顶指针
	LNode* p = L->next;//定义遍历指针
    //对称轴左边字符依次入栈
	for (i = 0; i < n / 2; i++) {
		S[i] = p->data;
		p = p->next;
	}
	i--;//变量 i 返回栈顶位置
	if (n % 2 == 1) {//若字符数为奇数则 p 向后遍历一步,因为最中间字符不需考虑
		p = p->next;
	}
	while (p != NULL) {//对称轴右边字符依次与栈顶元素比对
		if (p->data == S[i]) {//与栈顶元素相等则 p 继续遍历与下一出栈元素比较
			i--;//出栈
			p = p->next;//继续遍历
		}
		else//若不等,则说明 n 个字符不对称,直接返回 0
			return 0;//非中心对称
	}
	return 1;//若正常跳出循环,则证明 n 个字符对称,返回 1
}
02 假设一个算术表达式中包含小括号和中括号 2 种类型的括号,编写一个算法来判别表达式中的括号是否配对,假设算术表达式存放于字符数组中,以字符‘\0’作为算术表达式的结束符。
  1. 本题中对于数字和运算符不需要进行操作
  2. switch语句从上往下依次执行,因此需要break跳出;
  3. 遇到右括号时候,首先得判断栈是否为空,为空则说明不匹配了;
  4. 若数组遍历完成后栈为空,则证明所有左括号全部配对成功
int BracketsCheck(char a[]) {
	Stack S;
	InitStack(S);
	char x;
	for (int i = 0; a[i] != '\0'; i++) {
		switch (a[i]) {
			case'('://若数组元素为左括号,则压栈继续遍历
				push(S, a[i]);
				break;
			case'[':
				push(S, a[i]);
				break;
			case')'://若元素为右括号,则需考虑是否有左括号与之配对
				if (IsEmpty(S) {
					return 0;//若栈空,则说明无左括号与之配对
				}
				else {
					Pop(S, x);
					if (x != '(') {//若栈不为空,则判断栈顶元素与当前括号是否配对
						return 0;
					}
                    //配对上了
					break;
				}
			case']':
				if (IsEmpty(S)) {
					return 0;
				}
				else {
					Pop(S, x);
					if (x != '[') {
						return 0;
					}
					break;
				}
			default://若数组元素不是括号则直接继续遍历
				break;
		}
	}
	if (IsEmpty(S)) {//若数组遍历完成后栈为空,则证明所有左括号全部配对成功
		return 1;
	}
	else {//若栈不为空,则证明有左括号未配对
		retun 0;
	}
}
03 两个栈 S1、S2 都采用顺序栈方式,并共享一个存储区[0,…,MaxSize-1],为了尽量利用空间,减少溢出的可能,可采用栈顶相向、迎面增长的存储方式。试设计写出此栈的定义和 S1、S2 有关入栈和出栈的操作算法。

​ 两个栈,需要两个栈顶指针,这里定义了top数组,一个top[0],一个top[1]

#define MaxSize 50
typedef struct{
	int data[MaxSize];
	int top[2];//一个top[0],一个top[1]指针
}DStack;

初始化

void InitDStack(DStack& S) {
	S.top[0] = -1;//初始化 S1 栈顶指针
	S.top[1] = MaxSize;//初始化 S2 栈顶指针
}

入栈

  1. 因为一个存储空间有两个栈,因此需要告诉是对哪个栈进行入栈操作,i就是用来区分哪个栈;
  2. 这里S[1]表示下面的栈,S[2]表示上面的栈
int push(int i, int x) {
	if (i < 0 || i>1) {
		return 0;//若 i 的输入不合法,则无法入栈
	}
	if (S.top[1] - S.top[0] == 1) {//若存储空间已满,则无法进行入栈操作
		return 0;
	}
	switch (i) {
		case 0:// S1 栈顶指针上移后入栈
			S.top[0]++;
			S.data[S.top[0]] = x;
			//S.data[++S.top[0]] = x;
			break;
		case 1:// S2 栈顶指针下移后入栈
			S.top[1]--;
			S.data[S.top[1]] = x;
			//S.data[--S.top[1]] = x;
			break;
	}
	return 1;
}

出栈

int pop(int i, int& x) {
	if (i < 0 || i>1) {
		return 0;
	}
	if (S.top[0] == -1 || S.top[1] == MaxSize) {//空栈
		return 0;
	}
	switch (i) {
        case 0:
            x = S.data[S.top[0]];
            S.top[0]--;//下面的栈往下移
            //x = S.data[S.top[0]--];
            break;
        case 1:
            x = S.data[S.top[1]];
            S.top[1]++;//上面的栈顶指针往上移
            //x = S.data[S.top[1]++];
            break;
        }
	return 1;
}

队列Queue

先进先出

​ 队列的结构体定义及其基本操作。

#define MaxSize 50
typedef struct {
	int data[MaxSize];//队列中存放数据类型为整型
	int front, rear;//队首指针和队尾指针
}Queue;
void InitQueue(Queue& Q) {//初始化队列
	Q.front = 0;
	Q.rear = 0;
}
int IsEmpty(Queue Q) {//判断队列是否为空
	if (Q.front == Q.rear)//若队首指针和队尾指针指向同一位置,则队列为空
		return 1;
	else
		return 0;
}

队列的入队和出队

这里队尾指针指向元素的后一个位置,详见入队出队操作

入队争对的是队尾指针,需要判断队满Q.rear == MaxSize

//顺序队列的入队和出队:
//这里队尾指针指向元素的后一个位置
int EnQueue(Queue& Q, int x) {//入队操作
	if (Q.rear == MaxSize)//若队满,则无法入队
		return 0;
	Q.data[Q.rear] = x;//变量 x 入队
	Q.rear++;//队尾指针后移
	return 1;//入队成功
}

出队争对的是队头指针,需要判断队空Q.front == Q.rear

int DeQueue(Queue& Q, int& x) {//出队操作
	if (Q.front == Q.rear)//若队空,则无法出队
		return 0;
	x = Q.data[Q.front];//变量 x 接收出队元素
	Q.front++;//队首指针后移
	return 1;//出队成功
}

循环队列

​ 由于之前Q.front == Q.rear判断队空,若循环,则既有判空,又有存满的意思,因此可以牺牲一个空间,使得Q.front == Q.rear只能用来判空。

判空Q.front == Q.rear

判满(Q.rear + 1) % MaxSize == Q.front(rear向后移一个是front的话,说明满了)

​ 队尾指针和队首指针往后移动的时候都需要+1取余文章来源地址https://www.toymoban.com/news/detail-685831.html

//循环队列的入队和出队:(牺牲一个存储空间)
int EnQueue(Queue& Q, int x) {//入队操作
	if ((Q.rear + 1) % MaxSize == Q.front)//若队满,则无法入队
		return 0;
	Q.data[Q.rear] = x;//变量 x 入队
	Q.rear = (Q.rear + 1) % MaxSize;//队尾指针后移
	return 1;//入队成功
}
int DeQueue(Queue& Q, int& x) {//出队操作
	if (Q.front == Q.rear)//若队空,则无法出队
		return 0;
	x = Q.data[Q.front];//变量 x 接收出队元素
	Q.front = (Q.front + 1) % MaxSize;//队首指针后移
	return 1;//出队成功
}
04 若希望循环队列中的元素都能得到利用,则需设置一个标志域 tag,并以tag的值为0或1来区分队头指针front和队尾指针rear相同时的队列状态是“空”还是“满”。试编写与此结构相应的入队和出队算法。
  1. 循环队列中,Q.front == Q.rear在原先是能判断队空和队满,因此上面牺牲一个空间进行特别处理;
  2. 本题通过设置标志域来判断是队空还是队满;
  3. 这里需要判断队满的只有入队的时候,因此每次入队后将tag变成1;需要判断队空的只有出队的时候,因此每次出队后将tag变成0;由于队空队满判断都需要进行Q.front == Q.rear的判断,因此因此当队首队尾指针不在同一个地方时候,不会进入这个判断,初始时应该将tag置为0。
  4. Q.front == Q.rear && Q.tag == 1和Q.front == Q.rear && Q.tag == 0的条件下挺强的,都是需要两个条件同时满足
typedef struct {
	int data[MaxSize];
	int front, rear;
	int tag;
}Queue;
void InitQueue(Queue& Q) {//初始化队列
	Q.front = 0;
	Q.rear = 0;
    Q.tag = 0;
}
int EnQueue(Queue& Q, int x) {
	if (Q.front == Q.rear && Q.tag == 1) {//若队满,则无法进行入队操作
		return 0;
	}
	Q.data[Q.rear] = x;
	Q.rear = (Q.rear + 1) % MaxSize;//队尾指针后移
	Q.tag = 1;//入队后可能会出现队满的情况,所以将 tag 标志域置为 1
	return 1;
}
int DeQueue(Queue& Q, int& x) {
	if (Q.front == Q.rear && Q.tag == 0) {
		return 0;//队空
	}
	x = Q.data[Q.front];
	Q.front = (Q.front + 1) % MaxSize;
	Q.tag == 0;//出队后可能会出现队空的情况,所以将 tag 标志域置为 0
	return 1;
}
05 Q 是一个队列,S 是一个空栈,实现将队列中的元素逆置的算法。
  1. 队列先进先出,栈后进先出,要将队列中元素逆置,因此可以依次将队列的元素出队入栈,当队列为空时,然后出栈入队就实现了逆置。
//Q 是一个队列,S 是一个空栈,实现将队列中的元素逆置的算法。
void Reverse(Queue& Q, Stack& S) {
	int x;
	while (!IsEmpty(Q)) {//出队列入栈
		DeQueue(Q, x);
		Push(S, x);
	}
	while (!IsEmpty(S)) {//出栈入队列
		Pop(S, x);
		EnQueue(Q, x);
	}
}

到了这里,关于数据结构例题代码及其讲解-栈与队列的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据结构_复杂度讲解(附带例题详解)

    数据结构是计算机科学中研究数据组织、存储、管理和操作的方法和原则。它涉及到各种不同的数据类型和数据组织方式,包括数组、链表、树、图等。数据结构的设计和实现可以影响到程序的效率和可靠性,因此是计算机科学中非常重要的一个领域。 (数据结构是计算机存

    2024年02月07日
    浏览(34)
  • java数据结构(哈希表—HashMap)含LeetCode例题讲解

      目录 1、HashMap的基本方法 1.1、基础方法(增删改查) 1.2、其他方法  2、HashMap的相关例题 2.1、题目介绍 2.2、解题 2.2.1、解题思路 2.2.2、解题图解 2.3、解题代码 HashMap 是一个散列表,它存储的内容是键值(key-value)映射。 HashMap 的 key 与 value 类型可以相同也可以不同,根据定

    2024年02月05日
    浏览(36)
  • 【数据结构】广度优先遍历(BFS)模板及其讲解

    🎊专栏【数据结构】 🍔喜欢的诗句:更喜岷山千里雪 三军过后尽开颜。 🎆音乐分享【勋章】 大一同学小吉,欢迎并且感谢大家指出我的问题🥰 目录   🎁定义 🎁遍历方法  🎁根据题目来理解BFS 🏳️‍🌈走迷宫 🏳️‍🌈思路 🏳️‍🌈代码(BFS模板) 🏳️‍🌈分

    2024年02月06日
    浏览(30)
  • 数据结构链表力扣例题AC(2)——代码以及思路记录

    给你单链表的头节点  head  ,请你反转链表,并返回反转后的链表。 AC方法1 代码思路 观察示例,1-2-3-4-5 == 5-4-3-2-1 要将箭头的方向都旋转,假设从左向右改变,第一步2-1,用两个指针 n1 和 n2 分别指向1和2,使 n2 指向 n1 就可以实现了,但是此时由于 2 之前保存的 3 的地址,

    2024年02月21日
    浏览(30)
  • 数据结构进阶篇 之 【二叉树】详细概念讲解(带你认识何为二叉树及其性质)

    有朋自远方来,必先苦其心志,劳其筋骨,饿其体肤,空乏其身,鞭数十,驱之别院 1.1 二叉树中组分构成名词概念 1.2 二叉树的结构概念 1.3 特殊的二叉树 2.1 顺序存储 2.2 链式存储 前言: 在你的想象中如果有一个“二叉树”会是什么样子呢? 顾名思义,现实中的二叉树我们

    2024年04月13日
    浏览(28)
  • 数据结构——栈与队列

    目录 一、栈 1.栈的定义  2.栈的分类与基本操作 1. 顺序栈 2.链栈 3.栈与递归的实现 1.递归的简单描述 2.递归过程及与栈的关联 3.递归过程示意图 二.队列 1.队列的定义  2.队列的分类与基本操作 1.顺序队列 2.链队列 3.循环队列 1.假溢出  2.循环队列 3.循环队列相关操作实现:

    2024年02月04日
    浏览(34)
  • 【数据结构】栈与队列

    栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。 进行数据插入和删除操作的一端称为栈顶,另一端称为栈底 。栈中的数据元素遵守后进先出 LIFO (Last In First Out) 的原则。 压栈:栈的插入操作叫做进栈/压栈/入栈, 入数据在栈顶 。 出栈:栈的删除操

    2024年02月13日
    浏览(28)
  • 数据结构和算法(4):栈与队列

    栈(stack)是存放数据对象的一种特殊容器,其中的数据元素按线性的逻辑次序排列,故也可定义首、末元素。 尽管栈结构也支持对象的插入和删除操作,但其操作的范围仅限于栈的某一特定端。 也就是说,若约定新的元素只能从某一端插入其中,则反过来也只能从这一端删

    2024年02月09日
    浏览(36)
  • 【数据结构】 栈与队列的相互实现

    队列与栈的操作算法是笔试面试中较为常见的题目。 本文将着重介绍平时面试中常见的关于队列与栈的应用题目,马上要进行秋招了。希望对你们有帮助 _😀 请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。 实现

    2024年02月10日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包