结构之美学习二《栈和队列》

原创 2012年03月26日 14:57:18

栈和队列其实是个抽象的数据类型。

对于他们的实现,既可以用数组,也可以用链表实现。

对于栈和队列,看书的时候可能仅仅只是了解的一个概念。

因为要在程序中真正运用上去,个人觉得又是一个高度的思想境界。

我只是看了书,了解基本概念。


一。栈

定义

栈是仅限在表尾进行插入和删除的操作线性表。
我们把允许插入和删除数据的一段称之为栈顶(top)。另一端称之为栈底(bottom)
不含任何数据元素的栈称为空栈。LIFO后进先出表。

1.栈的数组结构实现,也就是栈顺序存储结构定义。

typedef struct 
{
	ElemType data[MAX_SIZE];
	int top;
}SqStack;

栈的常见操作就是进栈push好出栈pop操作

Status push(SqStack * s, ElemType e)
{
	if(s->top == MAX_SIZE-1);//栈已经满了
	return error;
	//入栈
	s->top++;
	s->data[s->top] = e;
	return ok;
}

Status pop(SqStack * s, ElemType *e){
	if(s->top ==-1)
	return error;
	*e = s->data[s->top];
	s->top--;
	return ok;
}

对于栈的顺序结构实现,是有很多的局限性的。

之后有又提出一个概念是 共享栈。

两个栈共享空间。
栈的顺序存储结构就和线性表的顺序存储一样,同样存在对开辟的存储空间无法很好的确定。
如果此时有两个相同类类型的栈。他们各自用一个数组空间。此时极有可能其中一个栈想插入元素却要溢出了。

而另外一个栈还留有很多存储空间。此时可以稍微 改进下,让两个栈共享一个数组空间。
我们将数组的始端作为第一个栈的栈底,数组的末端最为另一个栈的栈底。两个栈都是像中间延伸。

Status Push(SqStack * s, ElemType e, int stackNumber)
{
	 if(s->top1+1 == s->top2);
    	return error;
	if(stackNumber == 1)
	{
	 s->data[++s->top1] = e;
	}
	else if(stackNumber == 2)
	{
	s->data[--s->top2] = e;
	}
	return ok;
}

2.栈的链式实现。

typedef struct StackNode
{
	ElemType data;
	struct StackNode *next;
}StackNode *LinkStackhead

typedef struct LinkStack
{
	LinkStackhead top;//栈顶指针
	int count;//元素个数
}

进栈和出栈操作

Status push(LinkStack * ls,ElemType e)
{
	LinkStackhead l = (LinkStack)malloc(sizeof(StackNode));//开辟一块存储空间
	l->data = e;//赋值
	l->next = ls->top;
	ls->top = l;
	ls->count++;
	return ok;
}

Status pop(LonkStack * ls ,ElemType *e)
{
	LinkStakchead h;
	if(ls->count == -1)
		return error;
	//*e = ls->top;
	h = ls->top
	ls->top = p->next;
	free(h)
	ls->count--;
	return ok;

}

栈的应用。

在现实中,先进后出的式的栈应用:比如文件浏览工具就是一个典型。

其次比如我们程序的执行顺序也是可以理解为一个栈的形式 。 A 方法中调用了B,B中调用了C。

那么要执行完这端代码,我们先按调用的顺序将A,B,C依次压入栈中,然后C  B  A依次pop出执行操作。

因此我们可以联想到一个最常见的应用场景,就是递归。

递归中有个必定听到过的的内容,就是Fibonacci数列。

斐波那契的递归函数。

int Fbi(int i){
if(i<2)
return i == 0?0:1
return Fbi(i-1)+Fbi(i-2);
}
即,我要取得该数列中的第i个数,必须先知道位于第 i-2和i-1这两个数,

于是就产生一个递归的算法。

在递归中要注意的算法必须有跳出的条件。

从代码可以看出,递归用到的是选择结构。

显然递归代码很优雅,但是优雅是要有代价的,他会不断调用和建立函数副本,耗费大量的时间和内存。
对于斐波那契数列求第i相的算法有一种改进的做法,

因为这边我们假设计算 i项的数,

那么要先求 i-1和i-2项的数,

求i-1项的数则又需要求i-2和i-3项数;

到这边,我们就看出来了,在求i项时,我们去计算了 i-2项,在求i-1项时,我们有去求了i-2项。

也就是说,其实在计算第i项数,不停的递归时,很多计算都是重复的。

那么觉得可以考虑是否把每项的数在一次计算后就存起来,后面被调用到时在先去查找该项是否已经计算,有的话就直接取出来,不存在那就计算咯

private  Map numsMap = new HashMap<Integer,Integer>();
	public  int Fbi(int i){
	int x,y;
	if(i<2)
	return i == 0?0:1;
	if(numsMap.get(Integer.valueOf(i-1)) !=null){
		x = (Integer) numsMap.get(Integer.valueOf(i-1));
		}else{
			x=Fbi(i-1);
		}
	if(numsMap.get(Integer.valueOf(i-2)) !=null){
		y = (Integer) numsMap.get(Integer.valueOf(i-2));
		}else{
			y=Fbi(i-2);
		}
	return x+y;
	}

抱歉我的java和C的混写。因为C的话语法不是太熟,为了测试,熟练度java写起来比较快。

这也算是空间换时间的一种做法。


     栈另外一个重要的的应用:四则运算表达式求值。
1.后缀表示法,(逆波兰):简单说就是遇到数字就进栈,遇到符号就栈顶两个数字出栈。
2.中缀表达式也就是我们平常书写的四则运算表达式。
后缀表达式虽简单,但是怎么把一个中缀表达式转成一个后缀呢?
同样的,从左往右遍历,若是数字就输出,若是符号,判断其于栈顶符号的优先级,若是右括号或是优先级低于栈内元素的,

则栈顶元素依次出栈并输出,将当前符号进栈。


二:队列

定义

队列是只允许在一端进行插入操作,在另一端进行删除操作。FIFO线性表。

1.队列顺序存储结构

相对于栈在插入和删除上操作时间为O(1),在队列插入元素只是在数组末端追加一个元素,时间也为O(1),

但是如果是出列一个元素,此时后面的元素都需要往前面移动一个位置,时间就是O(N)。

因此提出了队头队尾指针。front指向队头元素,rear指向队尾元素的下一个位置。

但此时还是会出现一个问题,就是不停的出队入队,front和rear一直在往后移动,前面的数组单元空着,但是指针已移动到数组末尾,

此时造成一个假溢出的现象。

于是又提出一个改进思路,循环队列。

队列头尾相接的顺序存储结构称之为循环队列。
此时当在数组最后位置插入元素后,rear指针移动到数组的0的位置,既形成一个循环。
但是又会出现一个问题,在我继续插入元素,rear指针往后移动,就会有rear等于front的时候。上面我们说这个情况的队列是空队列出现矛盾,既我们无法判断当rear等于front时,队列到底是满呢,还是空的?
方法一:设置一个标志位Tag,rear还没有循环到数组0时,tag为0,循环到tag设置为1.
方法二:当队列空时rear = front,,当队列满时,我们保留一个元素空间
计算队列的长度通用公式:(rear -front +QueueSize)%QueueSize;
队列满的判断 (rear -front +QueueSize)%QueueSize ==front;

循环队列的顺序结构定义

typedef struct{
	ElemType data[MAX_SIZE];
	int front;
	int rear;
}SqQueue;

循环队列的入队出队操作

Status EnQueue(SqQueue *Q,ElemType e){
	if((Q->rear -Q->front +MAXSZIE)%MAXSIZE ==Q->front)
		return error;
	Q->data[Q->rear] = e;
	Q->rear = (Q->rear+1)%MAXSZIE;
		return ok;
	}

Status DeQueue(Sqqueue *Q,ElemType *e){
	if(Q->rear ==  Q->front)
		rerurn error;

	*e = Q- >data[Q->front];
	Q->front = (Q->front+1)%MAXSIZE;
		return ok;
}

2.队列的链式存储实现

链队列的结构
typedef int Elemtype ;
typedef struct QNode{
   ElemType data;
   struct QNode  *next;
}QNode,*QueuePtr;

typedef struct{//队列的链表结构
   Queueptr front,rear;

}LinkQueue;


链式队列的插入和删除

Status EnQueue(LinkQueue * Q , ElementType e)
{
	Queueptr p = (Queueptr) malloc(sizeof(QNode));

	if(!s)//分配失败;
		exit(OVERFLOW);

	p->data = e ;
	P->next = NULL;
	Q->rear->next = p ;//在队尾插入
	Q->rear = s ;//将p作为队尾节点
	return ok ;
}

Status DeQueue(LinkQueue * Q , ElementType *e)
{
	Queueptr p ;
	if( Q-> front == Q-> rear) //空队列
		return error;
	p = Q->front->next;//保存要删除的元素
	*e = p->data;
	Q->front->next = p->next;
	if(Q->rear == p)//若队头是队尾,删除后将队尾指向队头
	Q->rear = Q->front;
	free(p);
	eturn ok;
}





版权声明:本文为博主原创文章,未经博主允许不得转载。

数据结构实验二——栈和队列

1.1.编写一个程序,实现顺序栈的各种基本运算,并在此基础上设计一个主程序完成如下功能: (1)初始化栈s; (2)判断栈s是否为空; (3)依次进栈元素-1,2,10,-3,5; (4)判断...
  • u012736584
  • u012736584
  • 2015年05月08日 01:18
  • 945

非递归学习树结构(一)--栈和队列的实现

在开始学习树结构之前,有必要先学习一下栈和队列的知识,我们知道,在树结构中最让人头疼的就是各种递归,据传言,所有的递归都可以用栈来实现,因为递归的过程其实就是进栈出栈的过程,因此,可以把递归改写成对栈...
  • N_sev7
  • N_sev7
  • 2015年09月16日 20:17
  • 587

队列和栈的学习

本博客是java集合系列学习文章
  • u010504064
  • u010504064
  • 2014年12月27日 19:06
  • 734

【数据结构】——-栈、队列和数组(三)

本篇我们来介绍下数据结构中的数组: 在程序设计语言中,数组是我们较为熟悉的一种数据类型。几乎所有的程序设计语言都把数组类型设定为固定的类型。 一、数组的逻辑结构和基本运算 数组可...
  • singit
  • singit
  • 2017年04月14日 20:45
  • 556

数据结构学习总结(四)队列和栈

3.队列 队列其实可以看作是一种特别的线性表,一种对存储有特定要求的线性表。队列的特性就是FIFO——先进先出,就像平常的排队一样,先排队的先处理,队列中的进、出一般用PUSH、POP表示。队列是一种...
  • csdnligao
  • csdnligao
  • 2015年07月18日 20:45
  • 539

python中的队列和栈

在一个basicds模块里用实现了两个类:Stack和Queue及其各自所支持的操作。 队列是以排队的形式先进先出的序列集,栈是后进先出的序列集。 以下是模块basicds模块源码: basic...
  • u010700415
  • u010700415
  • 2014年03月12日 15:19
  • 984

栈与队列(五)链队列(链式结构)

队列(以链式为主) 定义:是只允许在一端进行插入操作,而在另一端进行删除操作的线性表 与栈(后进先出)不同,队列是先进先出 队头(删除的一端)(指头结点):出队列 队尾(插入的一端)(指an):入队...
  • w_linux
  • w_linux
  • 2017年02月11日 15:16
  • 322

java中栈和队列的实现和API用法

在java中要实现栈和队列,需要用到java集合的相关知识,特别是Stack、LinkedList等相关集合类型。 一、栈的实现 栈的实现,有两个方法:一个是用java本身的集合类型Stack类型;另...
  • ls5718
  • ls5718
  • 2016年06月17日 16:09
  • 2906

数据结构(二):线性表包括顺序存储结构(顺序表、顺序队列和顺序栈)和链式存储结构(链表、链队列和链栈)

还记得数据结构这个经典的分类图吧: pic1 今天主要关注一下线性表。 什么是线性表 线性表的划分是从数据的逻辑结构上进行的。线性指的是在数据的逻辑结构上是线性的。即在数据元素的非空有限集中 (1)...
  • LG1259156776
  • LG1259156776
  • 2015年07月21日 22:46
  • 2351

数据结构实验之栈六:下一较大值(二)

#include #include using namespace std; struct node { int data; int next;//记录下一个元素死亡值 i...
  • dreamzuora
  • dreamzuora
  • 2016年11月22日 13:08
  • 304
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:结构之美学习二《栈和队列》
举报原因:
原因补充:

(最多只允许输入30个字)