数据结构与算法 栈

一.栈模型

(Stack)又称后进先出表(LIFO List),是插入/删除操作被限制为只能在1个位置上进行的表.这个位置是表的末端,称为栈顶(Top).对栈的基本操作包括进栈(Push;在栈顶插入1个元素)和出栈(Pop;删除栈顶处的元素)
在这里插入图片描述

二.栈的实现
1.单链表实现:

在单链表实现下,所有操作均花费常数时间.这种实现的缺点在于malloc()free()的开销是昂贵的,尤其是与指针相比
#include <stdio.h>
#include <malloc.h>

typedef int ElementType;
struct Node;
typedef struct Node* PtrToNode;
typedef PtrToNode Stack;

int IsEmpty(Stack S);
Stack CreateStack(void);
void MakeEmpty(Stack S);
void Push(ElementType X, Stack S);
ElementType Top(Stack S);
void Pop(Stack S);

struct Node {
	ElementType Element;
	PtrToNode Next;
};

int main(void) {
	Stack S = CreateStack();
	Push(10,S);
	printf("%d\n",(S->Next->Element));//结果:10
	printf("%d\n",Top(S));//结果:10
	printf("%d\n",S->Next);//结果:11212160
	Pop(S);
	printf("%d\n",S->Next);//结果:0
}

int IsEmpty(Stack S) {//判断是否为空栈
	return S->Next == NULL;
}

Stack CreateStack(void) {//创建栈
	Stack S;
	S = malloc(sizeof(struct Node));
	if (S == NULL) {
		printf("Out of Space");//应该报错
	}
	S->Next==NULL;
	MakeEmpty(S);
	return S;//注意:S本身不储存元素,S->Next才是栈顶
}

void MakeEmpty(Stack S) {//清空栈
	if (S == NULL) {
		printf("Must Create Stack First");//应该报错
	} else {
		while (!IsEmpty(S)) {
			Pop(S);
		}
	}
}

void Push(ElementType X, Stack S) {//进栈
	PtrToNode TmpCell;
	TmpCell = malloc(sizeof(struct Node));
	if (TmpCell == NULL) {
		printf("Out of Memory");//应该报错
	} else {
		TmpCell->Element = X;
		TmpCell->Next = S->Next;
		S->Next = TmpCell;
	}
}

ElementType Top(Stack S) {//返回栈顶元素
	if (!IsEmpty(S)) {
		return S->Next->Element;
	}
	printf("Empty Stack");
	return 0;
}

void Pop(Stack S) {//出栈
	PtrToNode FirstCell;
	if (IsEmpty(S)) {
		printf("Empty Stack");
	} else {
		FirstCell = S->Next;
		S->Next = S->Next->Next;
		free(FirstCell);
	}
}

2.数组实现:

这种实现的缺点是需要事先声明数组的大小,因而会浪费一部分内存空间.这通常不是大问题,因为在典型的程序中,在任意时刻栈中元素的个数都不会太
多,数组通常也就不需要很大.如果不能保证这1,那么使用单链表实现就更合适.在数组实现下,所有操作均花费常数时间,甚至可能直接对应某条机器
指令,这体现了栈在计算机科学中有多么基本.错误检测十分影响栈的执行效率,所以有时会略去而使用其他方法来保证不越界,但通常还是会保留
#include <stdio.h>
#include <malloc.h>

typedef int ElementType;
struct StackRecord;
typedef struct StackRecord* Stack;

int IsEmpty(Stack S);
int IsFull(Stack S);
Stack CreateStack(int MaxElements);
void DisposeStack(Stack S);
void MakeEmpty(Stack S);
void Push(ElementType X, Stack S);
ElementType Top(Stack S);
void Pop(Stack S);
ElementType TopAndPop(Stack S);

#define EmptyTOS (-1)
#define MinStackSize (5)

struct StackRecord {
	int Capacity;//容量 
	int TopOfStack;//栈顶元素位置 
	ElementType * Array;//储存元素 
};

int main(void) {
	Stack S=CreateStack(10);
	Push(1,S);
	printf("%d\n",S->Array[S->TopOfStack]);//结果:1
}

int IsEmpty(Stack S) {//判断是否为空栈
	return S->TopOfStack == EmptyTOS;
}

int IsFull(Stack S) {//判断栈是否已满
	return S->TopOfStack == S->Capacity;
}

Stack CreateStack(int MaxElements) {//创建栈 
	Stack S;
	if (MaxElements < MinStackSize) {
		printf("Stack Size if Too Small");//应该报错
	} else {
		S = malloc(sizeof(struct StackRecord));
		if (S == NULL) {
			printf("Out of Space");//应该报错
		} else {
			S->Array = malloc(sizeof(ElementType) * MaxElements);
			if (S == NULL) {
				printf("Out of Space");//应该报错
			} else {
				S->Capacity = MaxElements;
			}
		}
	}
	MakeEmpty(S);
	return S;
}

void DisposeStack(Stack S) {//释放栈 
	if (S != NULL) {
		free(S->Array);
		free(S);
	}
}

void MakeEmpty(Stack S) {//清空栈 
	S->TopOfStack = EmptyTOS;
}

void Push(ElementType X, Stack S) {//进栈 
	if (IsFull(S)) {
		printf("Full Stack");//应该报错
	} else {
		S->Array[++S->TopOfStack] = X;
	}
}

ElementType Top(Stack S) {//返回栈顶元素 
	if (!IsEmpty(S)) {
		return S->Array[S->TopOfStack];
	}
	printf("Empty Stack");
	return 0;
}

void Pop(Stack S) {//出栈
	if (IsEmpty(S)) {
		printf("Empty Stack");
	}
	else {
		S->TopOfStack--;
	}
}

ElementType TopAndPop(Stack S) {//返回栈顶元素并出栈 
	if (!IsEmpty(S)) {
		return S->Array[S->TopOfStack--];
	}
	printf("Empty Stack");
	return 0;
}

三.应用
1.平衡符号:


2.后缀表达式:


3.中缀到后缀的转换:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值