王道数据结构【栈队列及其应用】部分代码实现(C语言)

数据结构专栏:

  1. 王道数据结构【顺序表】部分代码实现(C语言)
  2. 王道数据结构【链表】部分代码实现(C语言)
  3. 王道数据结构【栈队列及其应用】部分代码实现(C语言)
  4. 王道数据结构【二叉树】部分代码实现(C语言)
  5. 王道数据结构【图】部分代码实现(C语言)
  6. 王道数据结构【查找排序】部分代码实现(C语言)

判断链表是否中心对称

/*
	设单链表的表头指针为h,节点结构由data和next两个域构成,其中data域为字符型。
	试设计算法判断该链表的全部n个字符是否是中心对称,例如xyx,xyyx都是中心对称。

	分析:
		我们可以利用栈的先进后出的特性来搞定这道题,我们设置两个快慢指针,fast和slow
		之前我们就用过这种方法,用以找到中间节点,之后将slow节点之后的节点依次入栈,
		fast指针重新指向首节点,然后fast和栈内元素一一比较,若存在不同,则不对称。
*/
struct Link {
	union {
		char letter;
	}type;
	struct Link *next;
};
struct Stack {
	char *arr;
	int len;
	int top;
};
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
void isSymmetry(Link *h) {
	int size;
	struct Stack *s;
	Stack *createStack(int);
	bool push(Stack *,char);
	bool empty(Stack *);
	char *top(Stack *);
	bool pop(Stack *);
	void destory(Stack *);
	printf("请输入要创建的栈的大小:size=");
	scanf("%d",&size);
	s = createStack(size);
	struct Link *fast = h->next, *slow = h->next;
	while (fast->next&&fast->next->next) {
		fast = fast->next->next;
		slow = slow->next;
	}
	fast = h->next;
	while (slow->next) {//将中间元素的后面节点依次入栈
		push(s,slow->next->type.letter);
		slow = slow->next;//我总是忘记往下走
	}
	while (!empty(s)) {
		if (fast->type.letter != *top(s) ) {
			printf("该链表非中心对称");
			break;
		}
		fast = fast->next;
		pop(s);
	}
	if(empty(s))printf("该链表是中心对称的");
	destory(s);//最后销毁栈
}
int main() {
	struct Link *head;
	Link *createLink(int);
	head = createLink(1);
	isSymmetry(head);
	return 0;
} 

实现共享栈

/*
	设有两个栈s1、s2都采用顺序栈方式,并共享一个存储区,大小为max,为了尽量利用空间,减少溢出的可能,
	可采用栈顶相向、迎面增长的存储方式,试设计s1、s2有关入栈和出栈的算法。
	分析:
		
*/
#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
#define TYPE char 
struct Stack
{
	TYPE* arr;	//内存首地址
	int top[2]; 	//栈的下标
};

/* --------------以下为实现函数--------------------*/
//创建一个栈
Stack *createStack(int size) {
	struct Stack *stack = (struct Stack*)malloc(sizeof(struct Stack));//给栈分配空间
	stack->arr = (TYPE *)malloc(sizeof(TYPE)*size);//给内存首地址分配空间,大小用户指定
	stack->top[0] = -1;//栈顶下标,当前无元素,故为-1
	stack->top[1] = size;//栈顶下标,当前无元素,故为-1
	return stack;
}
//判断栈满
bool full(Stack *stack) {
	return stack->top[1]-stack->top[0] == 1;
}
//判断栈空
bool empty(int i,Stack *stack,int size) {
	switch (i) {
	case 0:
		return stack->top[0] == -1; 
	case 1:
			return stack->top[0] == size;

	}
}
//入栈(具体值)
bool push(Stack *stack, TYPE data,int i) {
	if (full(stack)) return false;
	switch (i) {
	case 0:
		*(stack->arr + ++stack->top[i]) = data;
	case 1:
		*(stack->arr + --stack->top[i]) = data;
	}
	return true;
}

//出栈
bool pop(int i,Stack *stack,int size) {
	if (empty(i,stack,size)) return false;
	switch (i) {
	case 0:
		stack->top[i]--;
	case 1:
		stack->top[i]++;
	}
	return true;

}

创建栈


#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
#define TYPE int
//#define TYPE biTree*
//#define TYPE char
//#define TYPE Recursion
struct biTree {
	char data;
	struct biTree *lchild;
	struct biTree *rchild;
};
struct Recursion {
	int no;
	int val;
};
struct Stack
{
	TYPE* arr;	//内存首地址
	int  len;	//栈的容量
	int top; 	//栈的下标
};

/* --------------以下为实现函数--------------------*/
//创建一个栈
Stack *createStack(int size) {
	struct Stack *stack = (struct Stack*)malloc(sizeof(struct Stack));//给栈分配空间
	stack->arr = (TYPE *)malloc(sizeof(TYPE)*size);//给内存首地址分配空间,大小用户指定
	stack->len = size;//栈容量
	stack->top = -1;//栈顶下标,当前无元素,故为-1
	return stack;
}
//判断栈满
bool full(Stack *stack) {
	return stack->top + 1 >= stack->len;
}
//判断栈空
bool empty(Stack *stack) {
	return stack->top == -1;
}
//入栈
bool push(Stack *stack, TYPE p) {
	if (full(stack)) return false;
	*(stack->arr + ++stack->top) = p;
	return true;
}

//出栈
bool pop(Stack *stack) {
	if (empty(stack)) return false;
	stack->top--;
	return true;

}

//查看栈顶元素
TYPE top(Stack *stack) {
	if (empty(stack)) return NULL;
	return *(stack->arr + stack->top);
}

//销毁
void destory(Stack *stack) {
	free(stack->arr);
	free(stack);

}
//判断是否含有某个元素
bool contain(Stack *stack, TYPE r) {
	if (empty(stack)) return false;
	for (int i = stack->top; i >= 0; i--) {
		if (r == *(stack->arr + i) ){//疯了,我居然把==写成了=
			return true;
		}
	}
	return false;
}

创建链队

/*
	此文件用于创建一个链式队列
	分析:
		我们需要创建一个链表,然后设置front、rear指针,用来模拟入队出队的过程
*/
//#define TYPE biTree* 
#define TYPE char
//#define TYPE int
struct biTree {//新增树节点
	char data;
	struct biTree *lchild;
	struct biTree *rchild;

};
struct Link {
	//TYPE data;
	TYPE node;
	struct Link *next;
};
struct LinkQueue {
	struct Link *front, *rear;
};
#include <stdio.h>
#include <stdlib.h>

//创建一个空链表
Link* createLink() {
	int n, data;
	char letter;
	struct Link *q;
	struct Link *head = (struct Link*) malloc(sizeof(struct Link));
	head->next = NULL;
	q = head;
	return head;
}
//创建链队
LinkQueue *create() {
	struct Link *h,*p;
	struct LinkQueue *lq=(struct LinkQueue *)malloc(sizeof(struct LinkQueue));
	h = createLink();
	p = h->next;
	lq->front = lq->rear = h;
	return lq;
}
//判断空
bool isEmpty(LinkQueue *lq) {
	return lq->front == lq->rear;
}
//入队
bool enQueue(LinkQueue *lq,TYPE data) {//队尾插入
	struct Link *newd = (struct Link *)malloc(sizeof(struct Link));
	newd->node = data;
	lq->rear->next = newd;
	lq->rear = newd;
	lq->rear->next = NULL;
	return true;
}
//出队
bool deQueue(LinkQueue *lq,TYPE *data) {
	if (isEmpty(lq))return false;
	struct Link *p = lq->front->next;//保存下一个节点
	*data = lq->front->next->node;//取出队首节点值
	lq->front->next = p->next;//删除队首节点
	if (lq->rear==p) {
		lq->rear = lq->front;
	}
	free(p);
	return true;
}
//打印队列中元素
void printQ(LinkQueue *lq) {
	Link *p = lq->front->next;
	while (p!=NULL) {
		printf("%c",p->node);
		p = p->next;
	}
};

tag队列

/*
	若希望循环队列中的元素都能得到利用,则需设置一个标志域tag,并以tag 的值为0或1来区分队头指针front和队尾指针rear
	相同时的队列状态是“空”还是“满”。试编写此结构相应的入队和出队算法。
	分析:
		
*/
#include <stdio.h>
#include <stdlib.h>
#define TYPE int 
struct Squeue {
	TYPE *arr;
	int front, rear;
	int tag;
};

//创建队列
Squeue *create(int n) {
	struct Squeue *sq = (struct Squeue *)malloc(sizeof(struct Squeue));
	sq->arr = (TYPE *)malloc(sizeof(TYPE)*n);//数组大小
	sq->front = 0;
	sq->rear = 0;
	sq->tag = 0;
	return sq;
}
//判断队满
bool isFull(Squeue *sq, int maxSize) {
	return (sq->rear == sq->front) && (sq->tag == 1);
}
//判断队空
bool isEmpty(Squeue *sq) {
	return (sq->front == sq->rear) && sq->tag==0;
}
//判断队列中元素个数
int count(Squeue *sq, int maxSize) {
	return (sq->rear - sq->front + maxSize) % maxSize;
}
//入队
bool enQueue(Squeue *sq, int data, int maxSize) {
	if (isFull(sq, maxSize)) return false;
	sq->arr[sq->rear] = data;
	sq->rear = (sq->rear + 1) % maxSize;
	sq->tag = 1;
	return true;
}
//出队
bool deQueue(Squeue *sq, int &data, int maxSize) {
	if (isEmpty(sq)) return false;
	data = sq->arr[sq->front];
	sq->front = (sq->front + 1) % maxSize;
	sq->tag = 0;
	return true;
}

利用栈逆置队列中的元素

//createStack.cpp

#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
#define TYPE int
//#define TYPE biTree*
//#define TYPE char
//#define TYPE Recursion
struct biTree {
	char data;
	struct biTree *lchild;
	struct biTree *rchild;
};
struct Recursion {
	int no;
	int val;
};
struct Stack
{
	TYPE* arr;	//内存首地址
	int  len;	//栈的容量
	int top; 	//栈的下标
};

/* --------------以下为实现函数--------------------*/
//创建一个栈
Stack *createStack(int size) {
	struct Stack *stack = (struct Stack*)malloc(sizeof(struct Stack));//给栈分配空间
	stack->arr = (TYPE *)malloc(sizeof(TYPE)*size);//给内存首地址分配空间,大小用户指定
	stack->len = size;//栈容量
	stack->top = -1;//栈顶下标,当前无元素,故为-1
	return stack;
}
//判断栈满
bool full(Stack *stack) {
	return stack->top + 1 >= stack->len;
}
//判断栈空
bool empty(Stack *stack) {
	return stack->top == -1;
}
//入栈
bool push(Stack *stack, TYPE p) {
	if (full(stack)) return false;
	*(stack->arr + ++stack->top) = p;
	return true;
}

//出栈
bool pop(Stack *stack) {
	if (empty(stack)) return false;
	stack->top--;
	return true;

}

//查看栈顶元素
TYPE top(Stack *stack) {
	if (empty(stack)) return NULL;
	return *(stack->arr + stack->top);
}

//销毁
void destory(Stack *stack) {
	free(stack->arr);
	free(stack);

}
//判断是否含有某个元素
bool contain(Stack *stack, TYPE r) {
	if (empty(stack)) return false;
	for (int i = stack->top; i >= 0; i--) {
		if (r == *(stack->arr + i) ){//疯了,我居然把==写成了=
			return true;
		}
	}
	return false;
}

括号匹配

// createStack.cpp
#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
#define TYPE int
//#define TYPE biTree*
//#define TYPE char
//#define TYPE Recursion
struct biTree {
	char data;
	struct biTree *lchild;
	struct biTree *rchild;
};
struct Recursion {
	int no;
	int val;
};
struct Stack
{
	TYPE* arr;	//内存首地址
	int  len;	//栈的容量
	int top; 	//栈的下标
};

/* --------------以下为实现函数--------------------*/
//创建一个栈
Stack *createStack(int size) {
	struct Stack *stack = (struct Stack*)malloc(sizeof(struct Stack));//给栈分配空间
	stack->arr = (TYPE *)malloc(sizeof(TYPE)*size);//给内存首地址分配空间,大小用户指定
	stack->len = size;//栈容量
	stack->top = -1;//栈顶下标,当前无元素,故为-1
	return stack;
}
//判断栈满
bool full(Stack *stack) {
	return stack->top + 1 >= stack->len;
}
//判断栈空
bool empty(Stack *stack) {
	return stack->top == -1;
}
//入栈
bool push(Stack *stack, TYPE p) {
	if (full(stack)) return false;
	*(stack->arr + ++stack->top) = p;
	return true;
}

//出栈
bool pop(Stack *stack) {
	if (empty(stack)) return false;
	stack->top--;
	return true;

}

//查看栈顶元素
TYPE top(Stack *stack) {
	if (empty(stack)) return NULL;
	return *(stack->arr + stack->top);
}

//销毁
void destory(Stack *stack) {
	free(stack->arr);
	free(stack);

}
//判断是否含有某个元素
bool contain(Stack *stack, TYPE r) {
	if (empty(stack)) return false;
	for (int i = stack->top; i >= 0; i--) {
		if (r == *(stack->arr + i) ){//疯了,我居然把==写成了=
			return true;
		}
	}
	return false;
}

车厢调度

/*
	利用栈进行车厢调度,使软座全部位于硬座前面
	分析:
		原文题目较长,但仔细分析后,这道题是一类较为简单的题。这里其实也并不需要用到栈的先入后出的特性,仅仅需要将硬座
		暂存,让软座先出去而已,所以将栈换成其他结构也是可以的,只要能够暂存数据。但这里题目要求用栈。
		为了模拟列车座位,我们采用两个数组来存储,数组A为入口处火车,数组B为出口处火车,A内数据依次入栈,若为硬座则压入
		栈,若为软座则直接进入B,最后栈内元素全部出栈,入B,至此,完成要求。
*/
#include <stdio.h>
#include <stdlib.h>
struct Stack {
	char *arr;
	int len;
	int top;
};
void trainArrange(char *arrA,char *arrB,Stack *s) {//传入入口车厢,出口车厢,栈
	int i = 0, j = 0;
	char *c;//接收出栈硬座
	bool push(Stack *,char );
	char *top(Stack *);
	bool pop(Stack *);
	bool empty(Stack *);
	while (i<10) {
		if (arrA[i]=='H') {//硬座,入栈
			push(s,arrA[i]);
		}
		else {//软座,入B
			arrB[j++] = arrA[i];
		}
		i++;
	}
	while (!empty(s)) {//若栈中还有硬座,全部入B
		c = top(s);
		pop(s);
		arrB[j++] = *c;
	}

}
int main() {
	char arrA[10] = {'H','S','S','H','H','S','S','S','H','H' };//用H代表硬座,S代表软座
	char arrB[10] = { 0 };//B数组初始为空
	Stack *createStack(int);
	Stack *s;
	s = createStack(10);//创建栈
	trainArrange(arrA,arrB,s);
	for (int i = 0; i < 10;i++) {//打印重排后的车厢
		printf("%c",arrB[i]);

	}
	return 0;
}

利用栈实现递归函数的非递归计算

/*
	利用一个栈实现以下递归函数的非递归计算
	分析:
		这里我们需要使用栈的先进后出特性。我们可以看出,从n=2开始,每一个值便都与前两个值挂钩,且式子不变,我们
		可以从栈顶到栈底依次边出栈边计算,直至栈底,便可以得出最终结果。
		
*/
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
struct Recursion {
	int no;
	int val;
};
struct Stack {
	Recursion *arr;
	int len;
	int top;
};
int getP(Stack *s,int n,int x) {//该算法函数,传入栈,n和x
	if (n==0) {
		return 1;
	}
	int fv1 = 1, fv2 = 2 * x;
	for (int i = n; i >= 2;i--) {//将序号入栈,从上至下,从2到n
		s->top++;
		s->arr[s->top].no = i;
	}
	while (s->top>=0) {//边出栈边计算
		s->arr[s->top].val = 2 * x*fv2 - 2 * (s->arr[s->top].no - 1)*fv1;
		fv1 = fv2;
		fv2 = s->arr[s->top].val;
		s->top--;
	}
	return fv2;
}
int main() {
	Stack *s;
	//声明各类方法
	Stack *createStack(int);
	bool push(Stack *,Recursion *);
	bool full(Stack *);
	bool empty(Stack *);
	bool top(Stack *);
	bool pop(Stack *);

	int n, x;//题目所要用到的n和x
	int p;//用于接收结果
	printf("请输入n和x: \n");
	printf("n=");
	scanf("%d",&n);
	printf("x=");
	scanf("%d", &x);

	//创建大小为n的栈
	s = createStack(n);
	p=getP(s,n,x);
	printf("%d",p);
	return 0;
}

车辆调度

/*
	栈和队列应用最后一题:汽车轮渡,要求:每次10辆,客车优先于货车,每上4辆客车才能上1辆货车,客车不足4辆时,货车代替
	货车不足时,允许客车都上
	分析:
		这仍然是一类排序的问题,王道书上的解答可以,核心意思就是客车和货车分为两个队列,客车队列出4辆,紧接着货车
		队列出一辆;当出现客车不足时,出货车队列代替,当货车不足时,继续出客车队列。代码也不难实现,
		这里我想分享一下自己的想法,我们上一题做过货车车厢调整的算法,利用栈将软座调整到硬座的前面,这里我们可以仿造
		相当于我们要将客车调整到货车的前面,只是有限制,每4辆客车就需要插入一辆货车,而面对特殊情况,我们也可以很好
		地处理,直接将剩余车辆(无论客车还是货车)直接连接到队列后面。
		之后我们从队列中取10辆车即可
*/
#include <stdio.h>

struct Stack {
	int *arr;
	int len;
	int top;
};
void manageCar(int *arrCar, int *arrArrange, Stack *s) {
	int i = 0, passengerCar = 0, j = 0;
	int *c;//接收出栈硬座
	bool push(Stack *, int);
	int *top(Stack *);
	bool pop(Stack *);
	bool empty(Stack *);
	for (; arrCar[i] == 1 || arrCar[i] == 2; i++) {
		if (arrCar[i] == 2 && passengerCar < 4) {//如果是货车且之前还没有4辆客车,入栈
			push(s, arrCar[i]);
		}
		else {//若是客车,直接入arrArrange
			if (passengerCar == 4) {//若之前已有连续4辆客车,出栈入货车
				if (!empty(s)) {
					c = top(s);
					pop(s);
					arrArrange[j++] = *c;
					passengerCar = 0;//重新计数
				}
			}
			arrArrange[j++] = arrCar[i];
			passengerCar++;//连续客车数加一
		}
	}
	while (!empty(s)) {//栈内元素不空,加入到arrArrange
		c = top(s);
		pop(s);
		arrArrange[j++] = *c;
	}

}
int main() {

	int arrCar[] = { 2,1,2,1,1,1,1,2,2,2,1,1 };//我们用1代表客车,用2发表货车,arrCar代表当前的车序列,然后我们需要重排
	int arrArrange[20] = { 0 };//初始化为0,接收重排的车队
	Stack *createStack(int);
	Stack *s;
	s = createStack(20);//创建一个栈
	manageCar(arrCar, arrArrange, s);
	for (int i = 0; i < 10; i++) {//取10辆车出来
		printf("%d ", *(arrArrange + i));
	}
	return 0;
}
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

落难Coder

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值