1.栈
1.1顺序栈
1.1.1定义
顺序栈从根本来讲就是拿数组来抽象出这个数据结构而已,所以,
在我们定义的时候如下:
#define STACK_LEN 5
typedefstructSqstack
{
intelem[STACK_LEN];
inttop;
}Sqstack,*Pstack;
1.1.2主要函数
voidInitStack(Pstackps);
boolPush(Pstackps,intval);
boolPop(Pstackps,intrtv);//删除
boolGetTop(Pstackps,intrtv);//得到栈顶元素,但是不删除
boolIsEmpty(Pstackps);
voidClear(Pstackps);//top 指针的操作
voidDestroy(Pstackps);//这里没有动态内存分配
1.1.3实现
#include<stdio.h>
#include"stack.h"
#include<assert.h>
void InitStack(Pstack ps)
{
assert(ps!=NULL );
ps->top=0;
}
static bool isFull(Pstack ps)
{
assert(ps!=NULL );
/*if(ps->top==STACK_LEN)
{
return true;
}
else
{
return false;
}
return true;*/
return ps->top==STACK_LEN;
}
bool Push(Pstack ps,int val)
{
assert(ps!=NULL );
if(isFull (ps))
{
return false;
}
ps->elem [ps->top++ ]=val;
return true;
}
bool IsEmpty(Pstack ps)
{
return ps->top==0;
}
bool Pop(Pstack ps,int *rtv)//删除
{
assert(ps!=NULL );
if(IsEmpty (ps))
{
return false;
}
if(rtv!=NULL )
{
ps->top--;
*rtv=ps->elem [ps->top ];
}
return true;
}
bool GetTop(Pstack ps,int *rtv)//得到栈顶元素, 但是不删除
{
assert(ps!=NULL );
if(IsEmpty (ps))
{
return false;
}
if(rtv!=NULL )
{
*rtv=ps->elem [ps->top-1];
}
return true;
}
void Clear(Pstack ps)//top 指针的操作
{
ps->top =0;
}
void Destroy(Pstack ps)//这里没有动态内存分配
{
Clear( ps);
}
void Show(Pstack ps)
{
for(int i=0;i<ps->top ;i++)
{
printf("%d ",ps->elem [i]);
}
printf("\n");
}
1.1.4练习
练习:一个栈的入栈序列为 ABCDEF,则不可能的出栈序列是(D)
A、DEFCBA B、DCEFBA C、FEDCBA
D、FECDBA E、ABCDEF F、ADCBFE
要点:1. 抓住栈的核心思想,先进后出。
2. 任何出栈的元素必须满足以下三点:
(1)在原序列中相对位置比它小的,必须是逆序;
(2)在原序列中相对位置比它大的,顺序没有要求;
(3)以上两点可以间插进行
1.2链式栈
1.2.1定义
见名思意,链式栈就是拿链表去实现的栈,入栈相当于头插法,每
次出栈只需要将头结点的数据出栈就好。
typedefstructNode
{
intdata;
structNode*next;
}Node,*Pstack;
1.2.2主要函数
voidInitStack(Pstackps);
boolPush(Pstackps,intval);
boolPop(Pstackps,intrtv);//删除
boolGetTop(Pstackps,intrtv);
boolIsEmpty(Pstackps);
voidDestroy(Pstackps);
1.2.3实现
#include<stdio.h>
#include"lstack.h"
#include<assert.h>
#include<stdlib.h>
void InitStack(Pstack ps)
{
assert(ps !=NULL );
ps->next =NULL ;
}
static Node *GetNode(int val)
{
Node *pGet=(Node *)malloc(sizeof (Node));
assert(pGet != NULL);
pGet ->data =val;
pGet ->next =NULL;
return pGet ;
}
bool Push(Pstack ps,int val)//头插法
{
Node* pGet=GetNode (val);
pGet->next=ps->next;
ps->next= pGet;
return true;
}
bool Pop(Pstack ps,int *rtv)//删除
{
if(IsEmpty (ps))
{
return false;
}
if(rtv !=NULL )
{
*rtv = ps->next->data;
}
Node *pDel = ps->next;
ps->next = pDel->next;
free(pDel);
pDel = NULL;
return true;
}
bool GetTop(Pstack ps,int *rtv)
{
if(IsEmpty(ps))
{
return false;
}
if(rtv != NULL)
{
*rtv = ps->next->data;
}
return true;
}
bool IsEmpty(Pstack ps)
{
return ps->next == NULL;
}
void Destroy(Pstack ps)
{
Node *p = NULL;
while(ps->next != NULL)
{
p = ps->next;
ps->next = p->next;
free(p);
}
p = NULL;
}
2.队列
2.1顺序队列
2.1.1注意问题
1、在讨论队列的时候,需要注意的是,因为是顺序队列,所以,其
出队的时间复杂度会变成 O(n),入队也是一样的,所以,我们将顺序
队列可以看做是环形的。
2、当看做环形之后,判断队空我们可以判断 queue->rear 是否等于
queue->front, 但 是 , 当 整 个 队 列 插 满 元 素 之 后 , 我 们 发 现
queue->rear+1 之后又等于 queue->front 了。所以在判断队列是否为
满的时候,需要这样判断:(queue->rear+1)%SIZE==queue->front;
3、值得注意的是,当我们把元素放入数组之后,并不可以直接++,
因为是环形的最后一个的下一个元素,可能是 0 号下标等等情况,所
以,每次下标应该是这样:queue->rear =(queue->rear+1)%SIZE;相
同的,出队也是一样的操作。
2.2.2定义
#defineSIZE8
typedefstructQueue
{
intelem[SIZE];
intfront;
intrear;
}Queue,*QueueS;
2.2.3主要函数
voidInitQueueS(QueueSqueue);
boolPush(QueueSqueue,intval);
boolPop(QueueSqueue,int*rtv);
voidShow(QueueSqueue);
intGetLength(QueueSqueue);
boolIsEmpty(QueueSqueue);
voidClear(QueueSqueue);
voidDestroy(QueueSqueue);
2.2.4实现
#include<stdio.h>
#include"Sqqueue.h"
#include<assert.h>
void InitQueueS(QueueS queue)
{
assert(queue != NULL);
queue->front = 0;
queue->rear = 0;
}
static bool IsFull(QueueS queue)
{
return (queue->rear+1)%SIZE == queue->front;
}
bool Push(QueueS queue,int val)
{
if(IsFull(queue))
{
return false;
}
queue->elem[queue->rear] = val;
queue->rear = (queue->rear+1)%SIZE;
return true;
}
bool Pop(QueueS queue,int *rtv)
{
if(IsEmpty(queue))
{
return false;
}
if(rtv != NULL)
{
*rtv = queue->elem[queue->front];
}
queue->front = (queue->front+1)%SIZE;
return true;
}
void Show(QueueS queue)
{
for(int i = queue->front; i != queue->rear;i = (i+1)%SIZE)
{
printf("%d ",queue->elem[i]);
}
printf("\n");
}
int GetLength(QueueS queue)
{
return (queue->rear-queue->front + SIZE)%SIZE;
}
bool IsEmpty(QueueS queue)
{
return queue->front == queue->rear;
}
void Clear(QueueS queue)
{
queue->front = queue->rear;
}
void Destroy(QueueS queue);
2.2链式队列
2.2.1定义
1、所谓链式队列就是运用单链表的思想去实现的队列。但是如果把
单链表实现队列,会有一个问题就是,尾插法入队的时间复杂度会是
O(n),出队 O(1),头插法入队,O(1),出队 O(n)这并不是我们想要的效果,
所以在链式队列里,我们的数据结构会是这个样子的。
2、首先,定义一个头结点,其包含两个域,next 和 last 域。Next 指
向第一个数据节点,last 指向最后一个数据节点,那么这样一来,他
的入队和出队的时间复杂度都为 O(1)了。
3.typedefstructHNode
{
structNodenext;
structNodelast;
}HNode,*QueueList;
typedefstructNode
{
int data;
struct Node *next;
}Node;
2.2.2主要函数
void InitQueueL(QueueList queue);
bool Push(QueueList queue,int val);
bool Pop(QueueList queue,int *rtv);
void Show(QueueList queue);
int GetLength(QueueList queue);
bool IsEmpty(QueueList queue);
void Clear(QueueList queue);
void Destroy(QueueList queue);
2.2.3实现
#include"lqueue.h"
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
void InitQueueL(QueueList queue)
{
assert(queue !=NULL);
queue->last = NULL;
queue->front = NULL;
}
static Node *GetNode(int val)
{
Node *pGet = (Node *)malloc(sizeof(Node));
assert(pGet != NULL);
pGet->data = val;
pGet->next = NULL;
return pGet;
}
bool Push(QueueList queue,int val)
{
Node *pGet = GetNode(val);
if(queue->last == NULL)//第一次插入
{
queue->front = pGet;
}
else
{
queue->last->next = pGet;
}
queue->last = pGet;
return true;
}
bool Pop(QueueList queue,int *rtv)
{
if(IsEmpty(queue))
{
return false;
}
if(rtv != NULL)
{
*rtv = queue->front->data;
}
Node *pDel = queue->front;
queue->front = pDel->next;
if(queue->front == NULL)
{
queue->last = NULL;
}
free(pDel);
pDel = NULL;
return true;
}
void Show(QueueList queue)
{
Node *p=queue->front ;
while(p !=NULL )
{
printf("%d ",p->data );
p=queue ->front ->next ;
}
printf("\n");
}
int GetLength(QueueList queue)
{
return (queue->front -queue->last + SIZE)%SIZE;
}
bool IsEmpty(QueueList queue)
{
if(queue->front == NULL || queue->last == NULL)
{
return true;
}
return false;
}
void Clear(QueueList queue)
{
}
void Destroy(QueueList queue)
{
}
3.练习(1、两个栈实现一个队列2、两个队列实现一个栈)
3.1两个栈实现一个队列
3.1.1实现
void pushQueue(Pstack s1,int val)
{
Push(s1,val);
}
int popQueue(Pstack s1,Pstack s2)
{
int tmp = 0;
if(IsEmpty(s2))
{
while(!IsEmpty(s1))
{
Pop(s1,&tmp);
Push(s2,tmp);
}
}
int tmp2 = 0;
if(!IsEmpty(s2))
{
Pop(s2,&tmp2);
}
else
{
printf("队列为空\n");
}
return tmp2;
}
int main()
{
Sqstack ps;
InitStack(&ps);
Sqstack ps2;
InitStack(&ps2);
pushQueue(&ps,2);
pushQueue(&ps,22);
pushQueue(&ps,12);
pushQueue(&ps,32);
int n1 = popQueue(&ps,&ps2);
printf("出队:%d \n",n1);//2
int n2 = popQueue(&ps,&ps2);
printf("出队:%d \n",n2);//22
int n3 = popQueue(&ps,&ps2);
printf("出队:%d \n",n3);//12
pushQueue(&ps,322);
//Show(&ps);
int n4 = popQueue(&ps,&ps2);
printf("n4==出队:%d \n",n4);//32
int n5 = popQueue(&ps,&ps2);
printf("出队:%d \n",n5);//322
int n6 = popQueue(&ps,&ps2);
printf("出队:%d \n",n6);
return 0;
}
3.2两个队列实现一个栈
3.2.1实现
void pushStack(Queue *qu1,Queue *qu2,int val)
{
Queue *p = NULL;//入队的队列
if(!IsEmpty(qu1))
{
p = qu1;
}
else
{
p = qu2;
}
Push(p,val);
}
int popStack(Queue *qu1,Queue *qu2)
{
Queue *p = NULL;//p将来出栈的队列
Queue *q = NULL;//q将来出栈的队列p,出出来的数据放到q所指的队列
if(!IsEmpty(qu1))
{
p = qu1;
q = qu2;
}
else
{
p = qu2;
q = qu1;
}
//p:出队的队列
//q指的是从p出出来的数据放到q里面
if(IsEmpty(p))
{
printf("栈为空\n");
return -1;
}
else
{
int tmp = 0;
while(GetLength(p) > 1)
{
Pop(p,&tmp);
Push(q,tmp);
}
Pop(p,&tmp);
return tmp;
}
}
int main()
{
Queue qu1;
InitQueueS(&qu1);
Queue qu2;
InitQueueS(&qu2);
pushStack(&qu1,&qu2,2);
pushStack(&qu1,&qu2,4);
pushStack(&qu1,&qu2,6);
pushStack(&qu1,&qu2,8);
int num = popStack(&qu1,&qu2);
printf("%d\n",num);//8
//pushStack(&qu1,&qu2,16);
//pushStack(&qu1,&qu2,18);
int num2 = popStack(&qu1,&qu2);
printf("%d\n",num2);//6
int num3 = popStack(&qu1,&qu2);
printf("%d\n",num3);//4
int num4 = popStack(&qu1,&qu2);
printf("%d\n",num4);//2
int num5 = popStack(&qu1,&qu2);
printf("%d\n",num5);//-1
return 0;
}
4.中缀表达式转化为后缀表达式
4.1定义
#pragma once
#define OPERATORS_PRIO_PLUS_IN 4 //栈内加法
#define OPERATORS_PRIO_SUB_IN 4 //栈内减法
#define OPERATORS_PRIO_MULTY_IN 2//栈内乘法
#define OPERATORS_PRIO_DIV_IN 2 //栈内除法
#define OPERATORS_PRIO_LEFT_BRAK_IN 10 //栈内左括号
#define OPERATORS_PRIO_PLUS_OUT 5 //栈外加法
#define OPERATORS_PRIO_SUB_OUT 5 //栈外减法
#define OPERATORS_PRIO_MULTY_OUT 3//栈外乘法
#define OPERATORS_PRIO_DIV_OUT 3 //栈外除法
#define OPERATORS_PRIO_LEFT_BRAK_OUT 1 //栈外左括号
#define OPERATORS_PRIO_RIGHT_BRAK_OUT 10 //栈外右括号
#define OPERATORS_PRIO_ERROR -1//错误运算符
void MiddleToLast(charstrLast,const charstrMid);
int Get_Prio(char opera,bool instack);
int Fun(int right,int left,char opera);
4.2实现
void MiddleToLast(char*strLast,const char*strMid)
{
int len= strlen(strMid);
char *stack = (char *)malloc(sizeof(char)*len);
assert(stack != NULL);
int top = 0;
int i = 0;//strLast的下标
//2+3*5-4*(5-3)
int prio_in = 0;//栈内的优先级
int prio_out = 0;//栈外的优先级
while(*strMid != '\0')
{
if(isdigit(*strMid))
{
strLast[i++] = *strMid++;
}
else//运算符,空格
{
if(top == 0)
{
stack[top++] = *strMid++;
}
else//栈不为空
{
prio_in = Get_Prio(stack[top-1],true);
prio_out = Get_Prio(*strMid,false);
if(prio_in < prio_out)//4 < 7
{
strLast[i++] = stack[--top];
}
else if(prio_in == prio_out)
{
--top;
strMid++;
}
else//prio_in > prio_out
{
stack[top++] = *strMid++;
}
}
}
}
while(top > 0)
{
strLast[i++] = stack[--top];
}
strLast[i] = '\0';
free(stack);
stack = NULL;
}
int Get_Prio(char opera,bool instack)
{
int prio = OPERATORS_PRIO_ERROR;
if(instack)
{
switch(opera)
{
case '+':
prio = OPERATORS_PRIO_PLUS_IN;
break;
case '-':
prio = OPERATORS_PRIO_SUB_IN;
break;
case '*':
prio = OPERATORS_PRIO_MULTY_IN;
break;
case '/':
prio = OPERATORS_PRIO_DIV_IN;
break;
case '(':
prio = OPERATORS_PRIO_LEFT_BRAK_IN;
break;
default:
prio = OPERATORS_PRIO_ERROR;
break;
}
}
else
{
switch(opera)
{
case '+':
prio = OPERATORS_PRIO_PLUS_OUT;
break;
case '-':
prio = OPERATORS_PRIO_SUB_OUT;
break;
case '*':
prio = OPERATORS_PRIO_MULTY_OUT;
break;
case '/':
prio = OPERATORS_PRIO_DIV_OUT;
break;
case '(':
prio = OPERATORS_PRIO_LEFT_BRAK_OUT;
break;
case ')':
prio = OPERATORS_PRIO_RIGHT_BRAK_OUT;
break;
default:
prio = OPERATORS_PRIO_ERROR;
break;
}
}
return prio;
}
4.3转化为后缀表达式后计算值
int Arithmeric(const char *strLast)//四则运算
{
int len = strlen(strLast);
int *stack = (int *)malloc(len);
assert(stack != NULL);
int top = 0;
int num1 = 0;
int num2 = 0;
int i = 0;//遍历后缀表达式
int result = 0;
while(i != len)
{
if(isdigit(strLast[i]))
{
stack[top++] = strLast[i]-'0';
}
else if(strLast[i] == ' ')
{
}
else//strLast[i] == 运算符
{
num1 = stack[--top];
num2 = stack[--top];
char opera = strLast[i];
result = Fun(num1,num2,opera);
stack[top++] = result;
}
i++;
}
return result;
}
int Fun(int right,int left,char opera)
{
switch (opera)
{
case'+':
return left+right;
case '*':
return left*right;
case'/':
return left/right;
case '-':
return left-right;
}
return 0;
}
4.4测试
int main ()
{
//((1+2)*(4-2)-1)*5-(2+2)*(3+3)
char *strMid = "2+3*5-4*(5-3)";
char strLast[30];
MiddleToLast(strLast,strMid);
printf("%s\n",strLast);//235*+453-*-
int result = Arithmeric(strLast);
printf("result == %d\n",result);
return 0;
}