- OS: Mac Catalina 10.15.4
- Hardware: Intel Core i9/16G 2667MHz DDR4
- 编译器版本:Mac Xcode 11.6
第03章 栈和队列
目录
例题
例题01 顺序栈的结构
#define StackSize 100 // 栈空间的大小应根据实际需要来定义,这里假设为100
typedef char DataType; // DataType的类型可根据实际情况而定,这里假设为char
typedef unsigned int list_size; // 定义栈大小的类型,这里定义的是无符号整型
typedef struct
{
DataType data[StackSize]; // 数组data用来存放表结点
list_size top; // 栈顶位置
}SeqStack;
SeqStack Stack;
例题02 置顺序栈为空栈
void InitStack(SeqStack *S)
{
S->top = 0;
}
程序示例:
int main(void)
{
SeqStack S;
InitStack(&S);
printf("顺序栈长度为:%d\n", S.top);
return 0;
}
程序运行结果:
例题03 判断顺序栈是否为空栈
// 判断顺序栈是否为空栈
// 参数:
// SeqStack *S: 顺序栈指针
// 返回:
// bool: 如果为空栈则返回true,否则返回false
bool IsEmpty(SeqStack *S)
{
return S->top == 0;
}
例题04 判断顺序栈是否为满栈
// 判断顺序栈是否为满栈
// 参数:
// SeqStack *S: 顺序栈指针
// 返回:
// bool: 如果为满栈则返回true,否则返回false
bool IsFull(SeqStack *S)
{
return S->top == StackSize;
}
例题05 顺序栈入栈
// 顺序栈入栈
// 参数:
// SeqStack *S: 顺序栈指针
// DataType item: 入栈一个元素
// 返回:
// void
void Push(SeqStack *S, DataType item)
{
// 如果已经满栈,则提示并返回
if (IsFull(S))
printf("[Stock overflow]\n");
else
{
S->data[S->top] = item; // 向栈定压入一个元素
S->top++; // 栈长度+1
}
}
程序示例:
int main(void)
{
SeqStack S;
int i;
InitStack(&S);
if (IsEmpty(&S))
printf("顺序栈是一个空栈.\n");
for (i = 1; i <= 100; i++)
Push(&S, (DataType)(96 + i));
if (IsFull(&S))
printf("顺序栈已经满栈.\n");
printf("顺序栈长度为:%d\n", S.top);
return 0;
}
程序运行结果:
例题06 顺序栈出栈
// 顺序栈出栈
// 参数:
// SeqStack *S: 顺序栈指针
// 返回:
// DataType: 返回栈顶元素,若栈为空则报错
DataType Pop(SeqStack *S)
{
if (IsEmpty(S))
{
printf("[Stack underflow]");
return (DataType)NULL;
} else
return S->data[--S->top];
}
示例程序:
int main(void)
{
SeqStack S;
int i;
InitStack(&S);
for (i = 1; i <= 5; i++)
Push(&S, (DataType)(96 + i));
printf("顺序栈出栈: ");
for (i = 1; i <= 5; i++)
printf("%c ", Pop(&S));
printf("\n顺序栈长度为:%d\n", S.top);
return 0;
}
程序执行结果:
例题07 顺序栈取栈顶元素
// 取栈顶元素
// 参数:
// SeqStack *S: 顺序栈指针
// 返回:
// DataType: 返回栈顶元素,若栈为空则报错
DataType GetTop(SeqStack *S)
{
if (IsEmpty(S))
{
printf("[Stack underflow]");
return (DataType)NULL;
} else
return S->data[S->top - 1]; // 返回栈顶元素
}
示例程序:
int main(void)
{
SeqStack S;
int i;
DataType c;
InitStack(&S);
printf("入栈数据: ");
for (i = 1; i <= 5; i++)
{
c = (DataType)(96 + i);
printf("%c ", c);
Push(&S, c);
}
printf("\n顺序栈出栈: ");
for (i = 1; i <= 5; i++)
printf("%c ", GetTop(&S));
printf("\n顺序栈长度为:%d\n", S.top);
return 0;
}
程序执行结果:
例题08 链式栈的结构
typedef int DataType; // DataType的类型可根据实际情况而定,这里假设为int
typedef struct stacknode
{
DataType data;
struct stacknode *next; // 指向下一个结点的指针
}StackNode;
typedef StackNode *LinkStack;
例题09 链式栈判断是否为空
// 判断链式栈是否为空
// 参数:
// LinkStack top: 链式栈栈顶指针
// 返回:
// bool: 如果为空,则表示已经到栈底为空栈返回true,否则返回false
bool isStackEmpty(LinkStack top)
{
return top == NULL;
}
例题10 链式栈入栈
// 插入栈顶元素
// 参数:
// LinkStack top: 链式栈栈顶指针
// DataType x: 入栈的值
// 返回:
// LinkStack: 新的栈顶指针
LinkStack Push(LinkStack top, DataType value)
{
StackNode *p;
p = (StackNode*)malloc(sizeof(StackNode)); // 申请新结点空间
p->data = value;
p->next = top; // 将新结点*p插入到栈顶
top = p; // 使top指向新的栈顶
return top; // 返回新栈顶指针
}
例题11 链式栈出栈
// 出栈
// 参数:
// LinkStack top: 链式栈栈顶指针
// DataType *x: 退栈的栈顶元素值
// 返回:
// LinkStack: 新的栈顶指针
LinkStack Pop(LinkStack top, DataType *value)
{
StackNode *p = top; // 保存栈顶指针
if (isStackEmpty(top)) // 判断栈是否为空
{
printf("[stack empty]");
return NULL;
} else
{
*value = p->data; // 保存删除结点的值,并带回
top = p->next; // 栈顶指针指向下一个结点
free(p); // 删除p指向的结点
return top; // 返回删除后的新的栈顶结点指针
}
}
例题12 链式栈取栈顶元素
// 取栈顶元素
// 参数:
// LinkStack top: 链式栈栈顶指针
// 返回:
// DataType: 栈顶元素值
DataType GetTop(LinkStack top)
{
if (isStackEmpty(top)) // 判断栈是否为空
{
printf("[stack empty]");
return (DataType)NULL;
} else
return top->data; // 返回栈顶结点值
}
程序实例:
int main(void)
{
LinkStack L = NULL;
int i;
DataType v;
if (isStackEmpty(L))
printf("链式栈是个空栈\n");
printf("入栈数据: ");
for (i = 1; i <= 5; i++)
{
printf("%d ", i);
L = Push(L, (DataType)i);
}
printf("\n栈顶数据为: %d", GetTop(L));
printf("\n出栈数据: ");
for(i = 1; i <= 5; i++)
{
L = Pop(L, &v);
printf("%d ", v);
}
printf("\n");
if (isStackEmpty(L))
printf("链式栈是个空栈\n");
return 0;
}
程序运行结果:
例题13 使用链式栈做圆括号匹配判定
bool isExpr()
{
LinkStack S = NULL; // 初始化栈
DataType ch, x;
ch = getchar();
while (ch != '\n')
{
if (ch == '(')
S = Push(S, ch); // 遇到左括号进栈
else
if (ch == ')')
{
if (isStackEmpty(S))
return 0;
else
S = Pop(S, &x);
}
ch = getchar();
} // end of while
return isStackEmpty(S);
}
示例程序:
int main(void)
{
printf("输入表达式(按回车确认):");
if (isExpr())
printf("圆括号匹配.\n");
else
printf("圆括号不匹配.\n");
}
运行结果:
例题14 使用顺序栈做回文判定
bool symmetry(char str[])
{
SeqStack S;
int j, k, i = 0;
InitStack(&S);
while (str[i] != '\0')
i++; // 求串的长度
for (j = 0; j < i / 2; j++)
Push(&S, str[j]); // 前一半字符串入栈
k = (i + 1) / 2; // 后一半字符在串中的起始位置
for (j = k; j < i; j++) // 后一半字符与栈中字符比较
{
if (str[j] != Pop(&S)) // 有不相同字符,则不对称
return false;
}
return true; // 完全相同,则对称
}
程序实例:
int main(void)
{
char str[100];
printf("输入一个字符串(<=100个字符,按回车确认):");
scanf("%s", str);
if (symmetry(str))
printf("回文\n");
else
printf("不是回文\n");
return 0;
}
程序执行结果:
例题15 使用顺序栈做进制转换
// 将一个非负的十进制数N转换成任意的d进制数
// 参数:
// unsigned int N: 非负的十进制数N
// unsigned short d: 任意的d进制数
// 返回:
// void
void conversion(unsigned int N, unsigned short d)
{
SeqStack S;
InitStack(&S);
DataType val;
// 以此将余数入栈
while (N)
{
val = N % d;
Push(&S, val);
N = N / d;
}
// 如果栈为非空,则依次出栈
while (!IsStackEmpty(&S))
{
val = Pop(&S);
if (d == 16) // 如果是转换为16进制,则10~15使用ABCDEF表示
{
if (val >= 10 && val <= 15)
printf("%c", 65 + (val - 10)); // 大写字母A~F
} else
printf("%d", val);
}
}
程序实例:
int main(void)
{
unsigned int N = 11259375;//十进制
printf("十进制非负整数: %u\n", N);
printf("转换成 八进制 进制为: ");
conversion(N, 8);
printf("\n转换成 二进制 进制为: ");
conversion(N, 2);
printf("\n转换成 二进制 进制为: ");
conversion(N, 16); printf("\n");
return 0;
}
程序输出结果:
例题16 栈的递归问题求解1,阶乘
long double fact(unsigned int n)
{
long double temp;
if (n == 0)
return 1;
else
temp = n * fact(n - 1);
return temp;
}
int main(void)
{
long double n;
n = fact(25);
printf("25! = %.0Lf\n", n);
}
程序输出结果:
注意:
- 使用long double类型并不能处理26!。
- 使用Mathematica可以计算超大的数据,比如100!,如下图:
例题17 栈的递归问题求解2,求函数
float fu(int n)
{
if (n < 2)
return (n + 1);
else
return fu(n / 2) * fu(n / 4);
}
int main(void)
{
int n = 10;
printf("fu() = %f\n", fu(n));
}
程序执行结果:
例题18 循环顺序队列结构定义
#define QueueSize 100
typedef char DataType; // 假设数据为字符型
typedef unsigned int list_size; // 队列长度类型
typedef struct
{
DataType data[QueueSize];
list_size front, rear;
list_size length;
}CirQueue;
例题19 循环顺序队列置空
// 置空队列
// 参数:
// CirQueue *Q: 循环队列指针
// 返回:
// void
void InitQueue(CirQueue *Q)
{
Q->front = Q->rear = Q->length = 0;
}
例题20 循环顺序队列判断是否为空
// 判断队列是否为空队列
// 参数:
// CirQueue *Q: 循环队列指针
// 返回:
// bool: 如果为空队列,则返回true,否则返回false
bool IsQueueEmpty(CirQueue *Q)
{
return Q->length == 0;
}
例题21 循环顺序队列判断是否队满
// 判断队列是否为满队列
// 参数:
// CirQueue *Q: 循环队列指针
// 返回:
// bool: 如果为满队列,则返回true,否则返回false
bool IsQueueFull(CirQueue *Q)
{
return Q->length == QueueSize;
}
例题22 循环顺序队列入队
// 入队列,插入元素value为队列Q新的队尾元素
// 参数:
// CirQueue *Q: 循环队列指针
// 返回:
// void
void EnQueue(CirQueue *Q, DataType value)
{
if (IsQueueEmpty(Q))
printf("[Queue overflow]");
else
{
Q->data[Q->rear] = value;
Q->rear = (Q->rear + 1) % QueueSize; // 循环意义下的加+1
Q->length++;
}
}
例题23 循环顺序队列取队头
// 取队头元素值
// 参数:
// CirQueue *Q: 循环队列指针
// 返回:
// DataType: 返回队列头值
DataType GetFront(CirQueue *Q)
{
if (IsQueueEmpty(Q))
{
printf("[Queue empty]");
return (DataType)NULL;
} else
return Q->data[Q->front];
}
例题24 循环顺序队列出队
// 出队列,删除Q的队头元素并返回其值
// 参数:
// CirQueue *Q: 循环队列指针
// 返回:
// DataType: 返回删除队头元素的值
DataType ExQueue(CirQueue *Q)
{
DataType value;
// 如果队列已经为空,则无法出队
if (IsQueueEmpty(Q))
{
printf("[Queue empty]");
return (DataType)NULL;
} else
{
value = Q->data[Q->front]; // 保存待删元素的值
Q->front = (Q->front + 1) % QueueSize; // 头指针+1
Q->length--;
return value;
}
}
测试程序:
int main(void)
{
CirQueue Q;
int i;
DataType value;
printf("开始初始化循环队列...\n");
InitQueue(&Q);
printf("初始化循环队列完成。队列容量=%d,队列成员个数=%d\n", QueueSize, Q.length);
printf("列表是否为空列表:%c 是否为满列表:%c\n",
(IsQueueEmpty(&Q) ? 'Y' : 'N'),
(IsQueueFull(&Q) ? 'Y' : 'N'));
printf("------------\n");
printf("开始入队5个元素...\n元素列表为:");
for (i = 1; i <= 5; i++)
{
printf("%c", (64 + i));
EnQueue(&Q, (DataType)(64 + i));
}
printf("\n队列容量=%d,队列成员个数=%d\n", QueueSize, Q.length);
printf("列表是否为空列表:%c 是否为满列表:%c\n",
(IsQueueEmpty(&Q) ? 'Y' : 'N'),
(IsQueueFull(&Q) ? 'Y' : 'N'));
printf("------------\n");
printf("出队3个元素...\n出队元素为:");
for (i = 1; i <= 3; i++)
{
value = ExQueue(&Q);
printf("%c", value);
}
printf("\n此时队列头的元素为:%c\n", GetFront(&Q));
printf("队列容量=%d,队列成员个数=%d\n", QueueSize, Q.length);
printf("列表是否为空列表:%c 是否为满列表:%c\n",
(IsQueueEmpty(&Q) ? 'Y' : 'N'),
(IsQueueFull(&Q) ? 'Y' : 'N'));
printf("------------\n");
printf("开始入队2个元素...\n元素列表为:");
for (i = 1; i <= 2; i++)
{
printf("%c", (69 + i));
EnQueue(&Q, (DataType)(69 + i));
}
printf("\n此时队列头的元素为:%c\n", GetFront(&Q));
printf("队列容量=%d,队列成员个数=%d\n", QueueSize, Q.length);
printf("列表是否为空列表:%c 是否为满列表:%c\n",
(IsQueueEmpty(&Q) ? 'Y' : 'N'),
(IsQueueFull(&Q) ? 'Y' : 'N'));
return 0;
}
程序输出结果:
注意:
- 这里使用的循环队列容量=5
- 定义了length成员,用来记录元素个数
例题25 带头结点的单向链式队列结构定义
typedef char DataType; // 假设数据为字符型
typedef struct qnode
{
DataType data;
struct qnode * next;
} QueueNode; // 链式队列结点类型
typedef struct
{
QueueNode *front; // 队头指针
QueueNode *rear; // 队尾指针
}LinkQueue;
例题26 带头结点的单向链式队构建
// 创建一个带头结点的单向链表
// 参数:
// LinkQueue *Q 未分配空间的链式队列
// 返回:
// void
void InitQueue(LinkQueue *Q)
{
Q->front = (QueueNode *)malloc(sizeof(QueueNode)); // 申请头结点空间
Q->rear = Q->front; // 尾结点也指向头结点
Q->rear->next = NULL;
}
例题27 带头结点的单向链式队列判断是否为空队
// 判断队列是否为空
// 参数:
// LinkQueue *Q 带头结点的单向队列
// 返回:
// bool 如果为空返回true否则返回false
bool IsQueueEmpty(LinkQueue *Q)
{
return Q->rear == Q->front; // 头尾指针相等队列为空
}
例题28 带头结点的单向链式队列入队
// 入队列
// 将元素item插入到链式队列的尾部
// 参数:
// LinkQueue *Q 带头结点的单向队列
// DataType 入队元素的数值
// 返回:
// void
void EnQueue(LinkQueue *Q, DataType item)
{
QueueNode *p = (QueueNode *)malloc(sizeof(QueueNode)); // 申请新结点
p->data = item;
p->next = NULL;
Q->rear->next = p; // *p链到原队尾结点之后
Q->rear = p; // 队尾指针指向新的队尾结点
}
例题29 带头结点的单向链式队列取队头元素
// 取队头元素
// 取链式队列的队头元素值
// 参数:
// LinkQueue *Q 带头结点的单向队列
// 返回:
// DataType 元素值
DataType GetFront(LinkQueue *Q)
{
if (IsQueueEmpty(Q))
{
printf("[Queue underflow]");
return (DataType)NULL; // 出错返回NULL
}
else
return Q->front->next->data; // 返回原队头元素值
}
例题30 带头结点的单向链式队列出队
// 删除链式队列的头结点,并返回头结点的元素值
// 参数:
// LinkQueue *Q 带头结点的单向队列
// 返回:
// DataType 被删除的头结点的元素值
DataType DeQueue(LinkQueue *Q)
{
QueueNode *p;
if (IsQueueEmpty(Q))
{
printf("[Queue underflow]");
return (DataType)NULL; // 出错返回NULL
}
else
{
p = Q->front; // p指向头结点
Q->front = Q->front->next; // 头指针指向原队头结点
free(p); // 删除释放原头结点
return(Q->front->data); // 返回原队头结点的数据值
}
}
例题31 带头结点的单向链式队列综合测试
int main(void)
{
int i;
QueueNode *p;
LinkQueue Q;
printf("初始化链式队列...\n");
InitQueue(&Q);
printf("初始化完成,队列是否为空: %s\n\n", IsQueueEmpty(&Q) ? "是" : "否");
printf("开始在队列尾入队A~G...\n");
for(i = 'A'; i <= 'G'; i++)
EnQueue(&Q, i);
printf("入队完成,队列是否为空: %s\n", IsQueueEmpty(&Q) ? "是" : "否");
p = Q.front->next;
i = 1;
if (p != NULL)
printf("队头元素值为: %c\n", GetFront(&Q));
printf("队列内容为: ");
while (p != NULL)
{
printf("[%d]=%c ", i++, p->data);
p = p->next;
}
printf("\n\n准备出队前3个元素...\n");
for (i = 1; i <= 3; i++)
DeQueue(&Q);
printf("删除完成,队列是否为空: %s\n", IsQueueEmpty(&Q) ? "是" : "否");
p = Q.front->next;
i = 1;
if (p != NULL)
printf("队头元素值为: %c\n", GetFront(&Q));
printf("队列内容为: ");
while (p != NULL)
{
printf("[%d]=%c ", i++, p->data);
p = p->next;
}
printf("\n\n删除剩余队列的所有元素...\n");
p = Q.front->next;
while (!IsQueueEmpty(&Q))
DeQueue(&Q);
printf("删除完成,队列是否为空: %s\n", IsQueueEmpty(&Q) ? "是" : "否");
return 0;
}
程序运行结果:
例题32 单向循环链式队列结构定义
typedef char DataType; // 假设数据为字符型
typedef struct qnode
{
DataType data;
struct qnode * next;
} QueueNode; // 链式队列结点类型
typedef struct
{
QueueNode *rear; // 队尾指针
}LinkQueue;
例题33 单向循环链式队列构建
// 创建一个带头结点的单向循环队列
// 参数:
// LinkQueue *Q 未分配空间的链式队列
// 返回:
// void
void InitQueue(LinkQueue *Q)
{
Q->rear = (QueueNode *)malloc(sizeof(QueueNode)); // 申请头结点空间
Q->rear->next = Q->rear;
}
例题34 单向循环链式队列判断是否为空
// 判断队列是否为空
// 参数:
// LinkQueue *Q 带头结点的单向队列
// 返回:
// bool 如果为空返回true否则返回false
bool IsQueueEmpty(LinkQueue *Q)
{
return Q->rear->next == Q->rear; // 头尾指针相等队列为空
}
例题35 单向循环链式队列入队
// 入队列
// 将元素item插入到链式队列的尾部
// 参数:
// LinkQueue *Q 带头结点的单向队列
// DataType 入队元素的数值
// 返回:
// void
void EnQueue(LinkQueue *Q, DataType item)
{
QueueNode *p = (QueueNode *)malloc(sizeof(QueueNode)); // 申请新结点
p->data = item;
p->next = Q->rear->next; // 新结点指向队列的头结点
Q->rear->next = p; // *p链到原队尾结点之后
Q->rear = p; // 队尾指针指向新的队尾结点
}
例题36 单向循环链式队列取队头元素
// 取队头元素
// 取链式队列的队头元素值
// 参数:
// LinkQueue *Q 带头结点的单向循环队列
// 返回:
// DataType 元素值
DataType GetFront(LinkQueue *Q)
{
if (IsQueueEmpty(Q))
{
printf("[Queue underflow]");
return (DataType)NULL; // 出错返回NULL
}
else
return Q->rear->next->next->data; // 返回原队头元素值
}
例题37 单向循环链式队列出队
// 删除链式队列的头结点,并返回头结点的元素值
// 参数:
// LinkQueue *Q 带头结点的单向队列
// 返回:
// DataType 被删除的头结点的元素值
DataType DeQueue(LinkQueue *Q)
{
QueueNode *h;
if (IsQueueEmpty(Q))
{
printf("[Queue underflow]");
return (DataType)NULL; // 出错返回NULL
}
else
{
h = Q->rear->next; // p指向头结点
Q->rear->next = h->next; // 头指针指向原队头结点
free(h); // 删除释放原头结点
return(Q->rear->next->data); // 返回原队头结点的数据值
}
}
例题38 单向循环链式队列综合测试
int main(void)
{
int i;
QueueNode *p;
LinkQueue Q;
printf("初始化链式队列...\n");
InitQueue(&Q);
printf("初始化完成,队列是否为空: %s\n\n", IsQueueEmpty(&Q) ? "是" : "否");
printf("开始在队列尾入队A~G...\n");
for(i = 'A'; i <= 'G'; i++)
EnQueue(&Q, i);
printf("入队完成,队列是否为空: %s\n", IsQueueEmpty(&Q) ? "是" : "否");
p = Q.rear->next->next;
i = 1;
if (!IsQueueEmpty(&Q))
printf("队头元素值为: %c\n", GetFront(&Q));
printf("队列内容为: ");
while (p != Q.rear->next)
{
printf("[%d]=%c ", i++, p->data);
p = p->next;
}
printf("\n\n准备出队前3个元素...\n");
for (i = 1; i <= 3; i++)
DeQueue(&Q);
printf("删除完成,队列是否为空: %s\n", IsQueueEmpty(&Q) ? "是" : "否");
p = Q.rear->next->next;
i = 1;
if (!IsQueueEmpty(&Q))
printf("队头元素值为: %c\n", GetFront(&Q));
printf("队列内容为: ");
while (p != Q.rear->next)
{
printf("[%d]=%c ", i++, p->data);
p = p->next;
}
printf("\n\n删除剩余队列的所有元素...\n");
p = Q.rear->next->next;
while (!IsQueueEmpty(&Q))
DeQueue(&Q);
printf("删除完成,队列是否为空: %s\n", IsQueueEmpty(&Q) ? "是" : "否");
return 0;
}
程序测试结果:
例题39 中缀表达式转后缀表达式
#include <stdio.h>
#include "SeqStack.h"
#include "LinkQueue.h"
int Priority(DataType op); // 操作符权限
void CTPostExp(LinkQueue *Q); // 中缀表达式转后缀表达式
int CPostExp(LinkQueue *Q); // 计算后缀表达式
int main(void)
{
LinkQueue Q;
QueueNode *p;
InitQueue(&Q);
printf("输入中缀表达式: ");
//9-(2+4*7)/5+3#
CTPostExp(&Q);
printf("后缀表达式为: ");
p = Q.front->next;
while (p != NULL)
{
printf("%c", p->data);
p = p->next;
}
printf("\n表达式计算结果为: %d\n", CPostExp(&Q));
return 0;
}
// 操作符权限优先级
int Priority(DataType op)
{
switch(op)
{
case '(':
case '#': return 0;
case '-':
case '+': return 1;
case '*':
case '/': return 2;
}
return -1;
}
// 中缀表达式转后缀表达式
void CTPostExp(LinkQueue *Q)
{
SeqStack S; // 运算符栈
char c, t;
InitStack(&S); // 初始化栈
Push(&S, '#'); // 压入栈底元素'#'
do // 扫描中缀表达式
{
c = getchar();
switch (c)
{
case ' ': break; // 去除空格富
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
EnQueue(Q, c);
break;
case '(':
Push(&S, c);
break;
case ')':
case '#':
do
{
t = Pop(&S);
if (t != '(' && t != '#')
EnQueue(Q, t);
}while (t != '(' && S.top != 0); break;
case '+':
case '-':
case '*':
case '/':
while (Priority(c) <= Priority(GetTop(&S)))
{
t = Pop(&S);
EnQueue(Q, t);
}
Push(&S, c);
break;
}
}while (c != '#'); // 以'#'号结束表达式扫描
}
int CPostExp(LinkQueue *Q)
{
SeqStack S;
char ch;
int x, y;
InitStack(&S);
while(!IsQueueEmpty(Q))
{
ch = DeQueue(Q);
if (ch >= '0' && ch <= '9')
Push(&S, ch - '0');
else
{
y = Pop(&S);
x = Pop(&S);
switch(ch)
{
case '+': Push(&S, x + y); break;
case '-': Push(&S, x - y); break;
case '*': Push(&S, x * y); break;
case '/': Push(&S, x / y); break;
}
}
}
return GetTop(&S);
}
输出结果:
编程练习
习题20
利用两个栈S1和S2模拟一个队列,如何用栈的运算来实现队列的插入和删除运算?试写出算法
typedef struct
{
SeqStack stack;
}StackQueue;
typedef StackQueue *node;
void InitQueue(StackQueue *Q)
{
InitStack(&Q->stack);
}
bool IsQueueEmpty(StackQueue *Q)
{
return IsStackEmpty(&Q->stack);
}
void EnQueue(StackQueue *Q, DataType item)
{
Push(&Q->stack, item);
}
DataType DeQueue(StackQueue *Q)
{
SeqStack S;
list_size p;
DataType item;
char c;
if (IsStackEmpty(&Q->stack))
{
printf("[Stack underflow]");
return (DataType)NULL;
} else
{
InitStack(&S);
p = Q->stack.top;
while (p-- > 1)
{
c = Pop(&Q->stack);
Push(&S, c);
}
item = Pop(&Q->stack);
while (!IsStackEmpty(&S))
Push(&Q->stack, Pop(&S));
}
return item;
}
int main(void)
{
StackQueue Q;
int i;
char c;
printf("开始初始化队列...\n");
InitQueue(&Q);
printf("初始化队列完成,开始向队列入队字母:A~G...\n");
for(c = 'A'; c <= 'G'; c++)
EnQueue(&Q, c);
printf("入队完成,队列成员为: ");
for(i = 0; i <= 'G' - 'A'; i++)
printf("[%d]=%c ", i + 1, Q.stack.data[i]);
printf("\n开始出队前3个...\n");
for (i = 1; i <= 3; i++)
printf("%c ", DeQueue(&Q));
printf("\n出队完成,剩余队列成员为: ");
for(i = 0; i <= 'G' - 'A' - 3; i++)
printf("[%d]=%c ", i + 1, Q.stack.data[i]);
printf("\n剩余队列全部出队...\n");
while (!IsQueueEmpty(&Q))
printf("%c ", DeQueue(&Q));
printf("\n出队完成,队列成员为:%s\n", IsQueueEmpty(&Q) ? "空" : "非空");
return 0;
}
程序执行结果:
习题21
试设计一个算法,实现输入一个字符串并检查字符串中是否含有圆括号,当圆括号匹配时输出括号内的字符串,否则给出出错信息(提示:利用栈记录左括号出现后的字符)。
#include <stdio.h>
#include <stdbool.h>
#include "LinkQueue.h"
int main(void)
{
char string[1024];
int i = 0;
char c;
bool sign = false;
LinkQueue Q;
InitQueue(&Q);
printf("输入一串字符串:");
scanf("%s", string);
do
{
c = string[i++];
if (c == '(')
sign = true;
else if (c == ')')
{
sign = false;
break;
}
else if (sign)
EnQueue(&Q, (DataType)c);
}while (c != '\0' || c != ')');
printf("括号中的内容为:\n");
while (!IsQueueEmpty(&Q))
printf("%c", DeQueue(&Q));
printf("\n");
return 0;
}
程序输出结果:
习题22
试利用循环队列(长度为k)存储,编写求斐波那契数列的前n(n>k)项()的算法,其函数定义如下:
#include <stdio.h>
#include "CirQueue.h"
int f(int n)
{
if (n < 0)
printf("ERROR!");
if (n == 0)
return 0;
else if (n == 1)
return 1;
else
return f(n - 2) + f(n - 1);
}
int main(void)
{
CirQueue Q;
int i;
InitQueue(&Q);
int k = 10, n;
printf("开始创建斐波那契数列, k = %d\n", k);
for (n = 0; n <= k; n++)
EnQueue(&Q, f(n));
printf("斐波那契数列列表:\n");
i = 0;
while (!IsQueueEmpty(&Q))
printf("f%d=%d ", i++, ExQueue(&Q));
printf("\n");
return 0;
}
程序输出结果:
对比数学软件Mathematica的运算结果: