一、栈
- 定义:只允许
一端
进行插入或者删除操作的线性表 - 特点:
LIFO后进先出
,像是一叠盘子,只能从上放,从上取. - 实现:
顺序存储实现
和链式存储实现
1.顺序存储实现代码
#include
#define MAX_SIZE 10
typedef struct {
int data[MAX_SIZE];
int top;
}Stack;
/**
* 初始化栈.
* @return 指向栈的指针.
*/
Stack* initStack();
/**
* 压栈.
* @param data 数据.
* @param stack 栈指针.
* @return true 成功,false失败.
*/
bool push(int data,Stack* stack);
/**
* 出栈.
* @param data 数据.
* @param stack 栈指针.
* @return true 成功,false失败.
*/
int pop(Stack* stack);
/**
* 已满.
* @param stack 栈指针.
* @return true 成功,false失败.
*/
bool isFull(Stack* stack);
/**
* 已空.
* @param stack 栈指针.
* @return true 成功,false失败.
*/
bool isEmpty(Stack* stack);
/**
* 展示栈元素.
* @param stack 栈指针.
*/
void showStack(Stack* stack);
int main() {
Stack* stack = initStack();
push(1,stack);
push(2,stack);
push(3,stack);
push(4,stack);
push(5,stack);
pop(stack);
pop(stack);
pop(stack);
pop(stack);
pop(stack);
pop(stack);
}
Stack* initStack() {
static Stack stack;
for(int i =0;i < MAX_SIZE; i++) {
stack.data[i] = 0;
}
stack.top = -1;
return &stack;
}
bool push(int data,Stack* stack) {
if(isFull(stack)) {
return false;
}
stack->data[++stack->top] = data;
showStack(stack);
return true;
}
bool isFull(Stack* stack) {
if(stack->top == MAX_SIZE -1) {
puts("栈已满");
return true;
}
return false;
}
bool isEmpty(Stack* stack) {
if(stack->top == -1){
return true;
}
return false;
}
void showStack(Stack* stack) {
for(int i = 0; i <= stack->top; i++) {
printf("%d ", stack->data[i]);
}
printf("\n");
}
int pop(Stack* stack){
if(isEmpty(stack)) {
puts("栈已空");
return false;
}
int popEle = stack->data[stack->top];
stack->data[stack->top--] = 0;
printf("popEle = %d\n",popEle);
showStack(stack);
return popEle;
}
2.带头结点链式存储实现.
#include
#include
typedef struct Node{
int data;
struct Node* next;
}Stack,Node;
/**
* 初始化栈.
* @return 指向栈的指针.
*/
Stack* initStack();
/**
* 压栈.
* @param data 数据.
* @param stack 栈指针.
* @return true 成功,false失败.
*/
bool push(int data,Stack* stack);
/**
* 出栈.
* @param data 数据.
* @param stack 栈指针.
* @return true 成功,false失败.
*/
int pop(Stack* stack);
/**
* 已空.
* @param stack 栈指针.
* @return true 成功,false失败.
*/
bool isEmpty(Stack* stack);
/**
* 展示栈元素.
* @param stack 栈指针.
*/
void showStack(Stack* stack);
/**
* 获取一个节点.
* @param data 数据.
* @return 节点.
*/
Node* getNode(int data);
int main() {
Stack* stack = initStack();
push(1,stack);
push(2,stack);
push(3,stack);
push(4,stack);
push(5,stack);
pop(stack);
pop(stack);
pop(stack);
pop(stack);
pop(stack);
pop(stack);
}
Stack* initStack(){
return getNode(0);
}
Node* getNode(int data){
Node* node = (Node*)malloc(sizeof(Node));
node->data = data;
node->next = NULL;
return node;
}
bool push(int data,Stack* stack) {
Stack* pointer = stack;
Node* node = getNode(data);
node->next = pointer->next;
pointer->next = node;
showStack(stack);
return true;
}
void showStack(Stack* stack) {
Stack* pointer = stack->next;
while(pointer != NULL) {
printf("%d ", pointer->data);
pointer = pointer->next;
}
printf("\n");
}
int pop(Stack* stack) {
if(isEmpty(stack)) {
return -1;
}
Node* freeNode = stack->next;
int popEle = freeNode->data;
stack->next = stack->next->next;
free(freeNode);
printf("popEle = %d\n",popEle);
showStack(stack);
return popEle;
}
bool isEmpty(Stack* stack){
if(stack->next == NULL) {
puts("栈已空");
return true;
}
return false;
}
3.感受
栈代码写起来要比线性表更加简单,以为毕竟栈是受限的线性表,砍掉了一些操作而已。
二、队列
- 定义: 只允许在一端进行插入,在另一端进行删除的线性表
- 特点:FIFO先进先出.
- 实现:
静态存储实现
,动态存储实现
.
1.静态存储实现的循环队列
#include
#define MAX_SIZE 10
typedef struct Queue{
int data[MAX_SIZE];
int front;
int rear;
}Queue;
/**
* 初始化队列.
* @return 队列指针.
*/
Queue* initQueue();
/**
* 入队.
* @param data 数据.
* @param queue 队列指针.
* @return true 成功,false失败.
*/
bool joinQueue(int data, Queue* queue);
/**
* 出队.
* @param data 数据.
* @param queue 队列指针.
* @return true 成功,false失败.
*/
bool leaveQueue(Queue* queue);
/**
* 判断队列已满.
* @param queue 队列指针.
* @return true 成功,false失败.
*/
bool isFull(Queue* queue);
/**
* 判断空队列.
* @param queue 队列指针.
* @return true 成功,false失败.
*/
bool isEmpty(Queue* queue);
/**
* 展示队列.
* @param queue 队列.
*/
void showQueue(Queue* queue);
int main() {
Queue* queue = initQueue();
joinQueue(1,queue);
joinQueue(2,queue);
joinQueue(3,queue);
joinQueue(4,queue);
joinQueue(5,queue);
joinQueue(6,queue);
joinQueue(7,queue);
joinQueue(8,queue);
joinQueue(9,queue);
joinQueue(10,queue);
leaveQueue(queue);
joinQueue(10,queue);
leaveQueue(queue);
leaveQueue(queue);
leaveQueue(queue);
leaveQueue(queue);
leaveQueue(queue);
leaveQueue(queue);
leaveQueue(queue);
leaveQueue(queue);
leaveQueue(queue);
leaveQueue(queue);
return true;
}
Queue* initQueue() {
static Queue queue;
for(int i =0; i < MAX_SIZE; i++) {
queue.data[i] = 0;
}
queue.front = 0;
queue.rear = 0;
return & queue;
}
bool isFull(Queue* queue) {
if((queue->rear + 1) % MAX_SIZE == queue->front) {
puts("队列已满");
return true;
}
return false;
}
bool isEmpty(Queue* queue) {
if(queue->front == queue->rear) {
puts("队列为空");
return true;
}
return false;
}
void showQueue(Queue* queue) {
int start = queue->front;
int end = queue->rear;
while(end != start){
printf("%d ",queue->data[start]);
start = (start + 1) % MAX_SIZE;
}
printf("\n");
}
bool leaveQueue(Queue* queue) {
if(isEmpty(queue)) {
return false;
}
int ele = queue->data[queue->front];
queue->front = (queue->front + 1) % MAX_SIZE;
printf("leave queue ele = %d\n",ele);
showQueue(queue);
return true;
}
bool joinQueue(int data, Queue* queue) {
if(isFull(queue)) {
return false;
}
queue->data[queue->rear] = data;
queue->rear = (queue->rear + 1) % MAX_SIZE;
showQueue(queue);
return true;
}
2.链式存储实现的队列.
#include
#include
#define MAX_SIZE 10
typedef struct Node{
int data;
struct Node* prior;
struct Node* next;
}Node;
typedef struct Queue{
Node* front;
Node* rear;
}Queue;
/**
* 初始化队列.
* @return 队列指针.
*/
Queue* initQueue();
/**
* 获取节点.
* @param data 数据.
* @return 节点指针.
*/
Node* getNode(int data);
/**
* 加入队列.
* @param data 数据.
* @param queue 队列指针.
* @return true 成功,false失败.
*/
bool joinQueue(int data,Queue* queue);
/**
* 离开队列.
* @param queue 队列指针.
* @return true 成功,false失败.
*/
bool leaveQueue(Queue* queue);
/**
* 展示队列.
* @param queue 队列指针.
*/
void showQueue(Queue* queue);
int main() {
Queue* queue = initQueue();
joinQueue(1,queue);
joinQueue(2,queue);
joinQueue(3,queue);
joinQueue(4,queue);
joinQueue(5,queue);
leaveQueue(queue);
leaveQueue(queue);
leaveQueue(queue);
leaveQueue(queue);
leaveQueue(queue);
}
Queue* initQueue() {
static Queue queue;
Node* node = getNode(0);
node->next = node;
node->prior = node;
queue.front = node;
queue.rear = node;
return &queue;
}
Node* getNode(int data) {
Node* node = (Node*)malloc(sizeof(Node));
node->prior = NULL;
node->next = NULL;
node->data = data;
return node;
}
bool joinQueue(int data,Queue* queue){
Node* node = getNode(data);
Node* pointer = queue->rear;
pointer->next = node;
node->prior = pointer;
node->next = queue->front;
pointer->prior = node;
queue->rear = node;
showQueue(queue);
return true;
}
void showQueue(Queue* queue) {
Node* pointer = queue->front->next;
while(pointer != queue->rear) {
printf("%d ",pointer->data);
pointer = pointer->next;
}
printf("%d\n",pointer->data);
}
bool leaveQueue(Queue* queue) {
if(queue->front == queue->rear) {
puts("队列已空\n");
return false;
}
Node* freeNode = queue->front;
queue->front = queue->front->next;
queue->front->prior = queue->rear;
queue->rear->next = queue->front;
int ele = queue->front->data;
free(freeNode);
printf("leave queue ele = %d\n",ele);
if(queue->front != queue->rear) {
showQueue(queue);
return true;
}
puts("队列已空");
return true;
}
三、栈的应用
- 中缀表达式转后缀
思想:
用栈存储尚未确定运算顺序的运算符和界限符.
待优化:
因为使用的是字符数组所以,目前只处理单个字符数字'0’,'1'...'9',多位数情况'10'尚不能处理。代码着重体现了中缀转后缀表达式的思想。
#include
#include
typedef struct Node{
char data;
struct Node* next;
}Stack,Node;
/**
* 初始化栈.
* @return 指向栈的指针.
*/
Stack* initStack();
/**
* 压栈.
* @param data 数据.
* @param stack 栈指针.
* @return true 成功,false失败.
*/
bool push(char data,Stack* stack);
/**
* 出栈.
* @param data 数据.
* @param stack 栈指针.
* @return true 成功,false失败.
*/
char pop(Stack* stack);
/**
* 已空.
* @param stack 栈指针.
* @return true 成功,false失败.
*/
bool isEmpty(Stack* stack);
/**
* 展示栈元素.
* @param stack 栈指针.
*/
void showStack(Stack* stack);
/**
* 获取一个节点.
* @param data 数据.
* @return 节点.
*/
Node* getNode(char data);
/**
* 中缀表达式转后缀表达式.
* @param stack 栈.
* @return 字符串.
*/
char * nifixToPostFix(Stack* stack);
int main() {
Stack* stack = initStack();
char* result = nifixToPostFix(stack);
puts(result);
}
Stack* initStack(){
return getNode(' ');
}
Node* getNode(char data){
Node* node = (Node*)malloc(sizeof(Node));
node->data = data;
node->next = NULL;
return node;
}
bool push(char data,Stack* stack) {
Stack* pointer = stack;
Node* node = getNode(data);
node->next = pointer->next;
pointer->next = node;
showStack(stack);
return true;
}
void showStack(Stack* stack) {
Stack* pointer = stack->next;
while(pointer != NULL) {
printf("%d ", pointer->data);
pointer = pointer->next;
}
printf("\n");
}
char pop(Stack* stack) {
if(isEmpty(stack)) {
return '#';
}
Node* freeNode = stack->next;
char popEle = freeNode->data;
stack->next = stack->next->next;
free(freeNode);
printf("popEle = %d\n",popEle);
showStack(stack);
return popEle;
}
bool isEmpty(Stack* stack){
if(stack->next == NULL) {
puts("栈已空");
return true;
}
return false;
}
// 使用栈存储暂时不能确定顺序的运算符.
char * nifixToPostFix(Stack* stack) {
char input[1024];
char postFixExpression[1024];
char* inputPointer = input;
char* pointer = postFixExpression;
char* string = postFixExpression;
puts("请输入表达式");
gets(input);
while(*inputPointer){
// 操作数直接加入后缀表达式.
char aim = *inputPointer;
if(aim >= '0' && aim <='9') {
*pointer = aim;
pointer++;
}
//遇到‘(’界限符,直接入栈.
if(aim == '(') {
push(aim, stack);
}
// 遇到界限符‘)’,说明之前肯定有‘(’在栈中,弹出栈中所有的运算符
// 并加入后缀表达式,直到遇到‘(’注意左括号不加入表达式.
if(aim == ')') {
char popEle = pop(stack);
while(popEle != '#') {
if(popEle == '('){
break;
}
*pointer = popEle;
pointer++;
popEle = pop(stack);
}
}
//遇到运算符,弹出高于或者等于当前运算符优先级的栈中运算符
//遇到栈空或者(结束,并将当前运算符加入栈中.
if(aim == '+' || aim == '-') {
//所有的运算符都曼度大于等于优先级顾直接弹出.
char popEle = pop(stack);
while(true) {
if(popEle == '#') {
break;
}
if(popEle == '(' ){
push(popEle, stack);
break;
}
*pointer = popEle;
pointer++;
popEle = pop(stack);
}
push(aim, stack);
}
if(aim == '*' || aim == '/') {
char popEle = pop(stack);
while(popEle == '*' || popEle =='/') {
*pointer = popEle;
pointer++;
popEle = pop(stack);
}
if(popEle == '+' || popEle == '-') {
push(popEle, stack);
}
push(aim, stack);
}
inputPointer++;
}
// 最后将队列中的全部运算符弹出并加入后缀表达式.
char popEle = pop(stack);
while(popEle != '#') {
*pointer = popEle;
pointer++;
popEle = pop(stack);
}
*pointer = '\0';
return string;
}
- 后缀表达式求值
思想:
用栈存储运算数,遍历表达式遇到运算符直接弹出两个运算数进行计算并压栈,重复操作,直到栈中还剩最后一个运算数,这就是结果。
int calculatePostFix(char* expression,Stack* stack) {
char* pointer = expression;
while(*pointer) {
char aim = *pointer;
if(aim >='0' && aim <= '9') {
push(aim - '0',stack);
}
if(aim == '+' ||aim == '-'||aim == '*'||aim == '/'){
int num1 = pop(stack);
int num2 = pop(stack);
int pushEle;
switch(aim){
case '+':{
pushEle = num2 + num1;
break;
}
case '-':{
pushEle = num2 - num1;
break;
}
case '*':{
pushEle = num2 * num1;
break;
}
case '/':{
pushEle = num2 / num1;
break;
}
}
push(pushEle, stack);
}
pointer++;
}
return pop(stack);
}
- 函数调用栈
- 递归
四、队列的应用
树的层序遍历.
图的广度优先遍历.
多个进程争抢有限系统资源,FCFS(先来先服务).