栈与队列都是数据结构的一种,只能在端口进行增删数据操作
栈的特点的先入后出
队列的特点的先入先出
栈
简单的栈(数组栈和链栈)
//1. 数组栈
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MaxIndex 100
typedef struct{
char data[MaxIndex];
int top;
}Stack;
//初始化数组栈
Stack *init(){
Stack *p = (Stack*)malloc(sizeof(Stack));
if(p == NULL)
return 0;
p->top=0;
return p;
}
//入栈
void push(Stack *p, char ch){
if(p->top >= MaxIndex){
printf("Overflow!\n");
return;
}
p->data[p->top] = ch;
p->top++;
}
//出栈
char pop(Stack *p){
if(p->top <= 0){
printf("Underflow!\n");
return NULL;
}
p->top--;
return p->data[p->top];
}
//栈满
bool isFull(Stack *p){
return p->top >= MaxIndex;
}
//栈空
bool isEmpty(Stack *p){
return p->top == 0;
}
//遍历打印栈元素
void printStack(Stack *p){
int index = p->top;
while(p->top--){
printf("%c", p->data[p->top]);
if(p->top){
printf(" ");
}else{
printf("\n");
}
}
p->top = index;
}
//2.链栈
#include<stdio.h>
#include<stdlib.h>
#define MaxIndex 100
typedef struct forename{
char data;
struct forename* next;
}Stack;
//初始化链栈
void init(Stack* p){
p->next=NULL;
}
//入栈
void push(Stack *p, char ch){
Stack *temp = (Stack*)malloc(sizeof(Stack));
temp->data = ch;
temp->next = p->next;
p->next = temp;
}
//出栈
char pop(Stack *p){
if(p->next == NULL){
printf("Underflow!\n");
return NULL;
}
Stack *temp = p->next;
char ch = temp->data;
p->next = temp->next;
free(temp);
return ch;
}
//栈空
bool isEmpty(Stack *p){
return p->next == NULL;
}
//遍历打印栈元素
void printStack(Stack *p){
Stack *temp = p;
while(temp->next != NULL){
printf("%c", temp->next->data);
temp = temp->next;
if(temp->next != NULL){
printf(" ");
}
}
printf("\n");
}
使用栈可以完成一写些比较复杂的操作,例如括号的匹配、算式格式转换(前缀、中缀、后缀之间的转换)
这里以数组栈为例,用链栈也是相同的
括号匹配完整代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MaxIndex 100
typedef struct{
char data[MaxIndex];
int top;
}Stack;
//初始化数组栈
Stack *init(){
Stack *p = (Stack*)malloc(sizeof(Stack));
if(p == NULL)
return 0;
p->top=0;
return p;
}
//入栈
void push(Stack *p, char ch){
if(p->top >= MaxIndex){
printf("Overflow!\n");
return;
}
p->data[p->top] = ch;
p->top++;
}
//出栈
char pop(Stack *p){
if(p->top <= 0){
printf("Underflow!\n");
return NULL;
}
p->top--;
return p->data[p->top];
}
//栈满
bool isFull(Stack *p){
return p->top >= MaxIndex;
}
//栈空
bool isEmpty(Stack *p){
return p->top == 0;
}
//遍历打印栈元素
void printStack(Stack *p){
int index = p->top;
while(p->top--){
printf("%c", p->data[p->top]);
if(p->top){
printf(" ");
}else{
printf("\n");
}
}
p->top = index;
}
//括号匹配
bool bracketsMatch(char brackets[]){
Stack *stack = init();
int n = strlen(brackets);
if(n%2){
return false;
}
for(int i=0; i<n; i++){
if(brackets[i] == '(' || brackets[i] == '{' || brackets[i] == '['){
push(stack, brackets[i]);
}else{
if(isEmpty(stack)){
return false;
}
char ch = pop(stack);
if(ch == '(' && brackets[i] != ')'){
return false;
}
if(ch == '[' && brackets[i] != ']'){
return false;
}
if(ch == '{' && brackets[i] != '}'){
return false;
}
}
}
return true;
}
int main(){
char str[20];
scanf("%s", str);
printf("Brackets match? %s", bracketsMatch(str) ? "true" : "false");
return 0;
}
表达式转换,这里只展示后缀表达式转中缀表达式,剩下两个都很简单。
后缀转中缀主要思路的是栈与二叉树相结合,遍历字符串,为数字则建树入栈,为运算符则建树,出栈两次,分别加为该树的左右子节点,再将此新树入栈,待遍历完成字符串,出栈,中序遍历该树,同时加括号。
注意,加括号的规则是:1. 根节点为乘除,子节点为加减,子节点的两个子节点两侧加括号 2. 根节点为减,右节点为加减,右节点的两个子节点两侧加括号
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MaxIndex 100
//二叉树
typedef struct TreeNode
{
char val;
struct TreeNode *left;
struct TreeNode *right;
} BiNode, *BiTree;
typedef struct
{
BiTree data[MaxIndex];
int top;
} Stack;
//初始化数组栈
Stack *init()
{
Stack *p = (Stack *)malloc(sizeof(Stack));
if (p == NULL)
return 0;
p->top = 0;
return p;
}
//入栈
void push(Stack *p, BiTree root)
{
if (p->top >= MaxIndex)
{
printf("Overflow!\n");
return;
}
p->data[p->top] = root;
p->top++;
}
//出栈
BiTree pop(Stack *p)
{
if (p->top <= 0)
{
printf("Underflow!\n");
return NULL;
}
p->top--;
return p->data[p->top];
}
//栈空
bool isEmpty(Stack *p)
{
return p->top == 0;
}
//二叉树创建
BiTree treeInit(char value)
{
BiTree root = (BiTree)malloc(sizeof(BiTree));
root->val = value;
root->left = NULL;
root->right = NULL;
return root;
}
//二叉树增加左节点
void addLeft(BiTree root, BiTree lnode)
{
if (root->left != NULL)
{
addLeft(root->left, lnode);
}
else
{
root->left = lnode;
}
}
//二叉树增加右节点
void addRight(BiTree root, BiTree rnode)
{
if (root->right != NULL)
{
addRight(root->right, rnode);
}
else
{
root->right = rnode;
}
}
//二叉树中序递归遍历(先左后右)
//加括号的规则是:1. 根节点为乘除,子节点为加减,子节点加括号 2. 根节点为减,右节点为加减,右节点加括号
void inOrder(BiTree root)
{
if (root == NULL)
{
return;
}
if ((root->val == '*' || root->val == '/') && (root->left->val == '+' || root->left->val == '-'))
{
printf("(");
inOrder(root->left);
printf(")");
}
else
{
inOrder(root->left);
}
printf("%c", root->val);
if (((root->val == '*' || root->val == '/') && (root->right->val == '+' || root->right->val == '-')) || root->val == '-' && (root->right->val == '-' || root->right->val == '+'))
{
printf("(");
inOrder(root->right);
printf(")");
}
else
{
inOrder(root->right);
}
}
//后缀表达式转中缀表达式(假定后缀表达式无括号)
void change(char exp[])
{
Stack *stack = init();
int n = strlen(exp);
for (int i = 0; i < n; i++)
{
if (exp[i] >= '0' && exp[i] <= '9')
{
push(stack, treeInit(exp[i]));
}
else
{
if (isEmpty(stack))
{
printf("Wrong!\n");
return;
}
BiTree c1, c2, c3;
c1 = pop(stack);
if (isEmpty(stack))
{
printf("Wrong!\n");
return;
}
c2 = pop(stack);
c3 = treeInit(exp[i]);
addLeft(c3, c2);
addRight(c3, c1);
push(stack, c3);
}
}
inOrder(pop(stack));
return;
}
int main()
{
char str[20];
scanf("%s", str);
change(str);
return 0;
}
队列
普通队列与栈相似,普通数组队列存在假溢出现象,链队列则不存在队满情况
链队列
#include<stdio.h>
#include<stdlib.h>
//链队列
typedef struct node {
char data;
node* next;
}QueueNode;
typedef struct queue {
QueueNode* front;
QueueNode* rear;
}Queue;
//初始化
Queue* init(){
Queue* que = (Queue*)malloc(sizeof(Queue));
que->front = (QueueNode*)malloc(sizeof(QueueNode));
que->rear = que->front;
que->front->next = NULL;
return que;
}
//队空
bool queueIsEmpty(Queue* que){
if(que->front == que->rear){
return true;
}
return false;
}
//入队
void enQueue(Queue* que, char ch){
QueueNode* p = (QueueNode*)malloc(sizeof(QueueNode));
p->data = ch;
p->next = NULL;
que->rear->next = p;
que->rear = p;
}
//出队
char outQueue(Queue* que){
QueueNode* p = que->front;
if(queueIsEmpty(que)){
return NULL;
}
char outch = p->next->data;
que->front = que->front->next;
free(p);
return outch;
}
//遍历打印
void printQueue(Queue* que){
QueueNode *p = que->front;
if(queueIsEmpty(que)){
printf("The queue is empty!");
return;
}
while((p = p->next) && p != que->rear->next){
printf("%c", p->data);
}
printf("\n");
return;
}
//测试样例7.
int main(){
Queue* myQueue = init();
printf("%s", queueIsEmpty(myQueue) ? "Queue is empty\n" : "Queue is not empty\n");
enQueue(myQueue, 'M');
enQueue(myQueue, 'y');
enQueue(myQueue, ' ');
enQueue(myQueue, 'q');
enQueue(myQueue, 'u');
enQueue(myQueue, 'e');
enQueue(myQueue, 'u');
enQueue(myQueue, 'e');
enQueue(myQueue, ' ');
enQueue(myQueue, 'i');
enQueue(myQueue, 's');
enQueue(myQueue, ' ');
enQueue(myQueue, 'c');
enQueue(myQueue, 'r');
enQueue(myQueue, 'a');
enQueue(myQueue, 'z');
enQueue(myQueue, 'y');
enQueue(myQueue, '!');
printQueue(myQueue);
for(int i = 0; i < 3; i++){
outQueue(myQueue);
}
printQueue(myQueue);
}
循环队列
#include<stdio.h>
#include<stdlib.h>
#define MAXNUM 100
//循环队列
typedef struct queue {
char data[MAXNUM];
int front, rear, length;
}loopQueue;
//初始化
void init(loopQueue* que){
que->front = 0;
que->rear = 0;
que->length = 0;
}
//队空
bool isEmpty(loopQueue* que){
if(que->length == 0){
return true;
}
return false;
}
//队满
bool isFul(loopQueue* que){
if (que->length == MAXNUM)
{
return true;
}
return false;
}
//队列长度
int queueLength(loopQueue* que){
return que->length;
}
//入队
void enQueue(loopQueue* que, char ch){
if(isFul(que)){
printf("The queue is full!\n");
return;
}
que->data[que->rear] = ch;
que->length++;
que->rear = (que->rear + 1) % MAXNUM;
}
//出队
char outQueue(loopQueue* que){
if (isEmpty(que))
{
printf("The queue is empty!\n");
return NULL;
}
char outch = que->data[que->front];
que->length--;
que->front = (que->front + 1) % MAXNUM;
return outch;
}
//遍历打印
void printQueue(loopQueue* que){
for(int i = 0; i < que->length; i++){
int x = (que->front + i)%MAXNUM;
printf("%c", que->data[x]);
}
printf("\n");
}
//测试样例
int main(){
loopQueue* myQueue;
init(myQueue);
printf("%s", isEmpty(myQueue) ? "Queue is empty\n" : "Queue is not empty\n");
enQueue(myQueue, 'M');
enQueue(myQueue, 'y');
enQueue(myQueue, ' ');
enQueue(myQueue, 'q');
enQueue(myQueue, 'u');
enQueue(myQueue, 'e');
enQueue(myQueue, 'u');
enQueue(myQueue, 'e');
enQueue(myQueue, ' ');
enQueue(myQueue, 'i');
enQueue(myQueue, 's');
enQueue(myQueue, ' ');
enQueue(myQueue, 'h');
enQueue(myQueue, 'a');
enQueue(myQueue, 'p');
enQueue(myQueue, 'p');
enQueue(myQueue, 'y');
enQueue(myQueue, '!');
printQueue(myQueue);
for (int i = 0; i < 3; i++)
{
outQueue(myQueue);
}
printQueue(myQueue);
}
至于队列应用举例,可以参考这篇博客:队列的应用