数据结构02栈和队列

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,int
rtv);//得到栈顶元素,但是不删除
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,int
rtv);
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;
structNode
last;
}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;
}

猜你喜欢

转载自blog.csdn.net/sunshinecandy/article/details/86244118