关于栈及其应用演示样例

转载请注明出处

http://blog.csdn.net/pony_maggie/article/details/30802249

作者:小马

作为一种经常使用的数据结构, 了解栈对于算法的学习是很必要的。

栈有先进后出的特点,栈底指向数据表中的第一个元素。栈顶指向最后一个元素的下一个位置。

例如以下图所看到的:

栈和线性表类似。也是有两种存储结构。分别为顺序结构和链式结构。

大部分情况下,栈使用前者。这和它的使用场景有关。由于通常情况下我们不会对栈进行频繁地。随机地插入,删除操作。以下是我用顺序结构实现的栈。这个栈有个特点就是它的通用性,由于我并没有限制它所存储的数据类型,代码例如以下:

//void**其为双指针,意味入栈和出栈的将仅仅是相应数据的地址。而不须要对数据本身进行拷贝
typedef struct
{
	char *base;
	char *top;
	int elementSize; //元素所点字节大小
	int stackSize;	//当前已分配的空间(注意不是元素的实际个数)
}ponyStack;

int InitStack(ponyStack *stack, int elementSize)
{
	stack->base = (char *)malloc(STACK_INIT_SIZE * sizeof(char)*elementSize);
	if (!stack->base)
	{
		return RET_ERROR;
	}

	stack->top = stack->base; //为空
	stack->stackSize = STACK_INIT_SIZE;
	stack->elementSize = elementSize;

	return RET_OK;
}

int ClearStack(ponyStack *stack)
{
	stack->top = stack->base;
	return RET_OK;
}

bool IsEmptyStack(ponyStack stack)
{
	if (stack.top == stack.base)
	{
		return true;
	}
	return false;
}

这里没有贴出所有的代码。更完整的能够从最后的地址那里下载。

注意elementSize,这个是栈能够做到通用的核心。

不理解的能够再研究一下代码。

看一个栈的使用演示样例,数制转换。十进制转八进制。

比如(1348)十进制= (2504)八进制,它基于例如以下的原理:

N             N/8             N%8

1348        168               4

168           21                0

21             2                  5

2               0                   2

所以非常明显,N不断的除8,每次的余数就是结果的当中一个因子,注意先出来的因子是低位的数。能够考虑用栈来保存每次取余的结果。那么出栈的顺序就是实际的结果顺序。代码非常easy:

int decimalToOctonary(int decimalNumber)
{
	double octNumber = 0;
	int nCount = 0;
	int nTemp = 0;
	ponyStack numberStack;
	InitStack(&numberStack, 4);

	while (decimalNumber)
	{
		nTemp = (int)decimalNumber%8;
		Push(&numberStack, &nTemp);
		decimalNumber = decimalNumber/8;
	}

	nCount = CountOfStack(numberStack);//元素个数也就是位数
	while(!IsEmptyStack(numberStack))
	{
		Pop(&numberStack, &nTemp);
		octNumber += (nTemp*pow(10.0, --nCount));
	}

	DestroyStack(&numberStack);

	return (int)octNumber;
}

再来看一个行编辑程序的演示样例,用户在终端输入字符。完毕后保存用户的数据区, 由于在输入的过程中可能出错,须要改动,所以不可能每输入一个字符就存入数据区。比較好的做法是先在内存里开一个输入的缓冲区,当用户输入完毕一行后,再存入数据区。在行内能够改动。比如。当用户发现刚输入的一个字符是错的之后。能够再输入一个‘#‘,表示前一个字符是错的,假设发现当前行输入的错误太多。能够输入一个退行符‘@‘,表示当前行都无效,举个样例:

whli#ilr#e(s#*s)

[email protected](*s=#++)

实际有效的字符是这种:

while(*s)

putchar(*s++)

能够把内存里这个输入缓冲区定为栈,正常情况下每输入一个字符直接入栈,假设发现字符是‘#‘,就栈顶pop一次。假设是‘@‘就清空栈.代码实现例如以下:

void lineEdit()
{
	char ch = 0;
	char chTemp = 0;
	ponyStack lineStack;
	InitStack(&lineStack, 1);

	ch = getchar();
	while (ch != EOF)
	{

		while (ch != EOF && ch != ‘\n‘)
		{
			switch (ch)
			{
			case ‘#‘:
				Pop(&lineStack, &chTemp);
				break;
			case ‘@‘:
				ClearStack(&lineStack);
				break;
			default:
				Push(&lineStack, &ch);
				break;
			}
			ch = getchar();
		}

		writeToFile(lineStack);//存数据
		ClearStack(&lineStack);//准备接收下一行
		if (ch != EOF)
		{
			ch = getchar();
		}
	}

	DestroyStack(&lineStack);

}

最后一个样例是表达式求值的算法。这个在计算器应用中比較多用到。

比方。

求+4*9-16/4

建两个栈,一个存操作数。一个存运算符.为简单起,在运算符栈会预先存一个‘#‘,表示表达式開始。然后以‘#‘结束。

运算规则是这种:

输入字符,假设是‘#‘。则结束,假设是操作数,直接进操作数栈。

假设是运算符。则跟栈顶的运算符比較,假设栈顶的优先级低,直接进栈,接收下一字符,假设相等。脱括号。接收下一个字符,假设栈顶的优先级高,pop两个操作数,pop栈内操作符。运算,然后运算的结果进操作数栈。

当前运算符继续跟栈顶比較。

要实现这个代码。首先要有一个表格。存储我们操作符之间的优先级关系,例如以下所看到的:

static char priority[7][7] = {
	‘>‘,‘>‘,‘<‘,‘<‘,‘<‘,‘>‘,‘>‘,   // +
	‘>‘,‘>‘,‘<‘,‘<‘,‘<‘,‘>‘,‘>‘,   // -
	‘>‘,‘>‘,‘>‘,‘>‘,‘<‘,‘>‘,‘>‘,   // *
	‘>‘,‘>‘,‘>‘,‘>‘,‘<‘,‘>‘,‘>‘,   // /
	‘<‘,‘<‘,‘<‘,‘<‘,‘<‘,‘=‘,‘ ‘,   // (
	‘>‘,‘>‘,‘>‘,‘>‘,‘ ‘,‘>‘,‘>‘,   // )
	‘<‘,‘<‘,‘<‘,‘<‘,‘<‘,‘ ‘,‘=‘,   // #
};// +   -   *   /   (   )   #

然后实现依据上面的思路,实现起来就比較easy了:

int evaluateExpression()
{
	char chCurrent = 0;
	char chOnTop = 0;

	char chTemp = 0;
	int nResult = 0;
	int nTemp = 0;
	int a,b;
	int nOperandFlag = 0;

	ponyStack operatorStack;//运算符栈
	ponyStack operandStack; //操作数栈

	InitStack(&operatorStack, 1);
	chTemp = ‘#‘;
	Push(&operatorStack, &chTemp);

	InitStack(&operandStack, 4);

	chCurrent = getchar();
	GetTop(operatorStack, &chOnTop);

	while ((chCurrent != ‘#‘)||(chOnTop != ‘#‘))
	{
		if (!isOperator(chCurrent))//是操作数,要考虑多位整型数的情况
		{
			nTemp = nTemp * (int)pow(10.0, nOperandFlag);
			nTemp += (int)(chCurrent - ‘0‘);
			chCurrent = getchar();
			nOperandFlag = 1;
		}
		else
		{
			if (nOperandFlag == 1)
			{
				Push(&operandStack, &nTemp);//操作数输入结束,入栈
				nOperandFlag = 0;
				nTemp = 0;
			}

			GetTop(operatorStack, &chOnTop);
			switch (precede(chOnTop, chCurrent))//比較优先级
			{
			case ‘<‘:		//栈顶的优先级小
				Push(&operatorStack, &chCurrent);
				chCurrent = getchar();
				GetTop(operatorStack, &chOnTop);
				break;
			case ‘=‘:		//脱括号。接收下个字符
				Pop(&operatorStack, &chTemp);
				chCurrent = getchar();
				GetTop(operatorStack, &chOnTop);
				break;
			case ‘>‘:		//栈顶的优先级大,出栈运算,结果入栈
				{
					Pop(&operandStack, &a);
					Pop(&operandStack, &b);
					Pop(&operatorStack, &chTemp);
					nTemp = operate(a, chTemp, b);
					Push(&operandStack, &nTemp);
					nTemp = 0;//重置
					GetTop(operatorStack, &chOnTop);
				}
				break;
			default:
				break;
			}

		}
	}

	GetTop(operandStack, &nResult);

	DestroyStack(&operatorStack);
	DestroyStack(&operandStack);

	return nResult;
}

代码下载地址:

https://github.com/pony-maggie/StackDemo

http://download.csdn.net/detail/pony_maggie/7499167

时间: 2024-11-14 13:36:50

关于栈及其应用演示样例的相关文章

内存损坏问题的演示样例及分析

原文以演示样例代码系统的讲述了三种内存损坏的情况: 全局内存.栈损坏及堆损坏, 以及它们产生的原因. 粗略整理例如以下. Global Memory Corruption 即全局变量的内存使用出了问题,主要还是越界. 例如以下代码: #include <stdio.h> #define MAX 6 int arrdata[MAX]; int endval; int main() { int i = 0; endval = 12; for (i = MAX; (endval) &&

展示C代码覆盖率的gcovr工具简单介绍及相关命令使用演示样例

(本人正在參加2015博客之星评选,诚邀你来投票,谢谢:username=zhouzxi">http://vote.blog.csdn.net/blogstar2015/candidate?username=zhouzxi) 近期,由于要展示某项目的单元測试的代码覆盖率.我无意间在网上找到了gcovr工具.使用之后,认为这个工具相当的不错,于是便写下这篇文章,可供相关的开发者參考. 简而言之,gcovr是一个将单元測试中的代码覆盖率以多种方式(包含列表方式.XML文件方式.HTML网页方式

最简单的视音频播放演示样例4:Direct3D播放RGB(通过Texture)

===================================================== 最简单的视音频播放演示样例系列文章列表: 最简单的视音频播放演示样例1:总述 最简单的视音频播放演示样例2:GDI播放YUV, RGB 最简单的视音频播放演示样例3:Direct3D播放YUV,RGB(通过Surface) 最简单的视音频播放演示样例4:Direct3D播放RGB(通过Texture) 最简单的视音频播放演示样例5:OpenGL播放RGB/YUV 最简单的视音频播放演示样例

PHPCMS中GET标签概述、 get 标签语法、get 标签创建工具、get 调用本系统演示样例、get 调用其它系统演示样例

一.get 标签概述 通俗来讲,get 标签是Phpcms定义的能直接调用数据库里面内容的简单化.友好化代码,她可调用本系统和外部数据,仅仅有你对SQL有一定的了解,她就是你的绝世好剑!也就是适合熟悉SQL语句的人使用.有了她,我们打造个性化的站点,能很方便的调用出数据库里面指定的内容.通过条件限制,我们能够调用出不同条件下的不同数据. 二.get标签样式 {get dbsource=" " sql=" "} {/get} 三.get 标签语法 1.get标签属性值

JDBC连接MySQL数据库及演示样例

JDBC是Sun公司制定的一个能够用Java语言连接数据库的技术. 一.JDBC基础知识         JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,能够为多种关系数据库提供统一訪问,它由一组用Java语言编写的类和接口组成.JDBC为数据库开发者提供了一个标准的API,据此能够构建更高级的工具和接口,使数据库开发者能够用纯 Java API 编写数据库应用程序,而且可跨平台执行,而且不受数据库供应商的限制.

java设计模式演示样例

创建模式 1.工厂方法模式(Factory Method)  将程序中创建对象的操作,单独出来处理,创建一个产品的工厂接口,把实际的工作转移到详细的子类.大大提高了系统扩展的柔性,接口的抽象化处理给相互依赖的对象创建提供了最好的抽象模式. public class TestFactoryMethod { public static void main(String[] args) { AnimalFactory af=new DogFactory(); Animal1 a=af.getAnima

Android线程池(二)——ThreadPoolExecutor及其拒绝策略RejectedExecutionHandler使用演示样例

MainActivity例如以下: package cc.vv; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import android.os.Bundle; import android.app.Activity; /** * Demo描写叙述: * 线程池(Threa

Android平台调用Web Service:演示样例

近期在学习Android,随着移动设备的流行,当软件走上商业化的道路.为了争夺市场,肯定须要支持Android的,所以開始接触了Android,只是仅仅了解皮毛就好,由于我们要做管理者嘛.懂点Android.管理起来easy些. Android学起来也简单,封装的更好了,一个个的控件,像是又回到了VB的赶脚. 以下将通过一个演示样例解说怎样在Android平台调用Web Service. 我们使用互联网现成的Webservice.供查询手机号码归属地的Web service,它的WSDL为htt

C编程规范, 演示样例代码。

/*************************************************************** *Copyright (c) 2014,TianYuan *All rights reserved. * *文件名: standard.h *文件标识: 编程规范演示样例代码 * *当前版本号:V1.0 *作者:wuyq *完毕日期:20140709 * *改动记录1: //改动历史记录.包含改动日期.版本号号.改动人及改动内容等 *改动日期 版本号号 改动人 改动内