数据结构-----栈

1.栈

1.1 栈的定义

栈是一种特殊的线性表。其特殊性在于限定插入和删除数据元素的操作只能在线性表的一端进行。如下所示:


结论:后进先出(Last In First Out),简称为LIFO线性表。

栈的基本运算有六种:

构造空栈:InitStack(S)、

判栈空: StackEmpty(S)、

判栈满: StackFull(S)、

进栈: Push(S,x)、可形象地理解为压入,这时栈中会多一个元素

退栈: Pop(S) 、 可形象地理解为弹出,弹出后栈中就无此元素了。

取栈顶元素:StackTop(S),不同与弹出,只是使用栈顶元素的值,该元素仍在栈顶不会改变。

    由于栈也是线性表,因此线性表的存储结构对栈也适用,通常栈有顺序栈链栈两种存储结构,这两种存储结构的不同,则使得实现栈的基本运算的算法也有所不同。

我们要了解的是,在顺序栈中有"上溢"和"下溢"的概念。顺序栈好比一个盒子,我们在里头放了一叠书,当我们要用书的话只能从第一本开始拿(你会把盒子翻过来吗?真聪明^^),那么当我们把书本放到这个栈中超过盒子的顶部时就放不下了(叠上去的不算,哼哼),这时就是"上溢","上溢"也就是栈顶指针指出栈的外面,显然是出错了。反之,当栈中已没有书时,我们再去拿,看看没书,把盒子拎起来看看盒底,还是没有,这就是"下溢"。"下溢"本身可以表示栈为空栈,因此可以用它来作为控制转移的条件。

链栈则没有上溢的限制,它就象是一条一头固定的链子,可以在活动的一头自由地增加链环(结点)而不会溢出,链栈不需要在头部附加头结点,因为栈都是在头部进行操作的,如果加了头结点,等于要在头结点之后的结点进行操作,反而使算法更复杂,所以只要有链表的头指针就可以了。


代码:

// Test.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"  
#include <iostream>
using namespace std;
#define MAX 10 // MAXIMUM STACK CONTENT
class stack   
{   
private:   
	int arr[MAX]; 
	int top; 
public:   
	stack() 
	{   
		inItStack(); 
	}
	/************************************************************************/
	/* 初始化栈                                                                     */
	/************************************************************************/
	void inItStack() 
	{ 
		top=-1; 
	} 
	/************************************************************************/
	/* 入栈                                                                     */
	/************************************************************************/
	void push(int a) 
	{   
		top++;
		if(top < MAX)  {   
			arr[top]=a; 
		}   else   {   
			cout<<"STACK FULL!!"<<top;   
		}   
	}   
	/************************************************************************/
	/* 出栈                                                                     */
	/************************************************************************/
	int pop()
	{    
		if(isEmpty())   {   
			cout<<"STACK IS EMPTY ";
			return NULL;   
		} else {   
			int data=arr[top]; 
			arr[top]=NULL; 
			top--;
			return data; 
		}   
	}   

	/************************************************************************/
	/* 是否为空                                                                     */
	/************************************************************************/
	bool isEmpty()
	{
		if(top == -1) return true;
		else return false;
	}
};   
int main()   
{   
	stack a;   
	a.push(3);   
	a.push(10);   
	a.push(1);   
	cout<<"Pop:"<<a.pop();      
	return 0;   
}

结论:由于栈的插入和删除操作具有它的特殊性,所以用顺序存储结构表示的栈并不存在插入删除数据元素时需要移动的问题,但栈容量难以扩充的弱点仍就没有摆脱。

1.3 栈的链式存储
若是栈中元素的数目变化范围较大或不清楚栈元素的数目,就应该考虑使用链式存储结构。人们将用链式存储结构表示的栈称作"链栈"。链栈通常用一个无头结点的单链表表示。如图所示:


栈的操作是线性表操作的特例。

简单用c实现:

// Test.cpp : Defines the entry point for the console application.  
//  
#include "stdafx.h"  
#include <stdio.h>  
#include "stdlib.h"
#include <iostream>
using namespace std;
//宏定义  
#define TRUE   1  
#define FALSE   0  
#define OK    1  
#define ERROR   0  
#define INFEASIBLE -1  
#define OVERFLOW -2 
#define STACKEMPTY -3  

#define LT(a,b)   ((a)<(b))  
#define N = 100         

typedef int Status;  
typedef int ElemType;  

typedef struct LNode{  
	ElemType		data;               
	struct LNode   *next;     
}LNode, *LinkList; 

typedef struct stack{
	LinkList top;
} STACK;


/************************************************************************/
/*     接口:
*/
/************************************************************************/
void InitStack(STACK &S);
void Push(STACK &S,ElemType e);
void Pop(STACK &S, ElemType *e);
ElemType GetTop(STACK S,ElemType *e);
int StackEmpty(STACK S);

/************************************************************************/
/* 
*/
/************************************************************************/
void InitStack(STACK &S)
{
	S.top=NULL;
}

/************************************************************************/
/* 入栈 
*/
/************************************************************************/
void Push(STACK &S,ElemType e)
{
	LinkList p;
	p = (LinkList )malloc(sizeof(LNode));
	if (!p) exit(OVERFLOW);
	p->data = e;
	p->next = S.top;
	S.top = p;
}
/************************************************************************/
/* 出栈
*/
/************************************************************************/
void Pop(STACK &S, ElemType *e)
{
	LinkList p;
	if(StackEmpty(S)) exit(STACKEMPTY);
	*e = S.top->data;
	p = S.top;
	S.top = p->next; 
	free(p);
}
/************************************************************************/
/* 获取栈顶元素内容
*/
/************************************************************************/
ElemType GetTop(STACK S, ElemType *e)
{
	if(StackEmpty(S)) exit(STACKEMPTY);
	*e = S.top->data;
}

/************************************************************************/
/* 判断栈S是否空 
*/
/************************************************************************/
int StackEmpty(STACK S) 
{
	if(S.top==NULL) return TRUE;
	return   FALSE;
}

void main()  
{  

	STACK S;
	InitStack( S);
	Push(S, 3);
	Push(S, 4);
	ElemType e;
	Pop(S,&e);
	cout<<"Pop elem:"<<e;
}  

1.4 栈的应用

1)  数制转换

2)语法词法分析

3)表达式求值等


1.5 栈的递归和实现

汉诺塔的问题:

解决:

1)如果有一个盘子,直接从X移到Z即可。
2)如果有n个盘子要从X移到Z,Y作为辅助。问题可以转化为,先将上面n-1个从X移动到Y,Z作为辅助,然后将第n个从X移动到Z,最后将剩余的n-1个从Y移动到Z,X作为辅助。

完整实现代码,包括栈的实现:

/ Test.cpp : Defines the entry point for the console application.  
//  
#include "stdafx.h"  
#include <stdio.h>  
#include "stdlib.h"
#include <iostream>
using namespace std;
//宏定义  
#define TRUE   1  
#define FALSE   0  
#define OK    1  
#define ERROR   0  
#define INFEASIBLE -1  
#define OVERFLOW -2 
#define STACKEMPTY -3  

#define LT(a,b)   ((a)<(b))  
#define N = 100         

typedef int Status;  
typedef int ElemType;  

typedef struct LNode{  
	ElemType		data;               
	struct LNode   *next;     
}LNode, *LinkList; 

typedef struct stack{
	LinkList top;
} STACK;


/************************************************************************/
/*     接口:
*/
/************************************************************************/
void InitStack(STACK &S);
void Push(STACK &S,ElemType e);
void Pop(STACK &S, ElemType *e);
ElemType GetTop(STACK S,ElemType *e);
int StackEmpty(STACK S);

/************************************************************************/
/* 
*/
/************************************************************************/
void InitStack(STACK &S)
{
	S.top=NULL;
}

/************************************************************************/
/* 入栈 
*/
/************************************************************************/
void Push(STACK &S,ElemType e)
{
	LinkList p;
	p = (LinkList )malloc(sizeof(LNode));
	if (!p) exit(OVERFLOW);
	p->data = e;
	p->next = S.top;
	S.top = p;
}
/************************************************************************/
/* 出栈
*/
/************************************************************************/
void Pop(STACK &S, ElemType *e)
{
	LinkList p;
	if(StackEmpty(S)) exit(STACKEMPTY);
	*e = S.top->data;
	p = S.top;
	S.top = p->next; 
	free(p);
}
/************************************************************************/
/* 获取栈顶元素内容 

*/
/************************************************************************/
ElemType GetTop(STACK S, ElemType *e)
{
	if(StackEmpty(S)) exit(STACKEMPTY);
	*e = S.top->data;
}
void printStack(STACK S){
	LinkList p;
	p = S.top;
	printf("栈: ");
	while (p) {
		printf("%d ", p->data);
		p = p->next;
	}
}
/************************************************************************/
/* 如果有一个盘子,直接从X移到Z即可。
如果有n个盘子要从X移到Z,Y作为辅助。问题可以转化为,先将上面n-1个从X移动到Y,Z作为辅助,然后将第n个从X移动到Z,最后将剩余的n-1个从Y移动到Z,X作为辅助。
*/
/************************************************************************/

void move(STACK &Sa,STACK &Sb)
{	
	ElemType e;
	Pop(Sa,&e);
	Push(Sb, e);
}
void hanoi(int n,STACK  &X,STACK &Y,STACK &Z)
{
	if(n==1) return move(X, Z);		//将圆盘1号直接移到z
	hanoi(n-1,X,Z,Y);				//将x上的1大n-1圆盘移到y,z做辅助塔
	move(X, Z);						//将编号为n的圆盘移z
	hanoi(n-1,Y,X,Z);			    //将y上的1大n-1圆盘移到z,x做辅助塔
}

/************************************************************************/
/* 判断栈S是否空 
*/
/************************************************************************/
int StackEmpty(STACK S) 
{
	if(S.top==NULL) return TRUE;
	return   FALSE;
}

void main()  
{  

	STACK Sx, Sy,Sz;
	InitStack( Sx);
	InitStack( Sy);
	InitStack( Sz);
	int i, n = 10;
	for (i = 10 ; i>=1 ;i--) {
		Push(Sx, i);
	}
	printStack(Sx);
	hanoi(n,  Sx,Sy,Sz);
	printStack(Sz);
}  


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
顺序是一种基于数组实现的,它的特点是具有随机存取的特性。顺序的基本运算包括进、出和查看顶元素。进操作将元素插入到顶,出操作将顶元素删除并返回,查看顶元素操作返回顶的元素值,但不修改的状态。 在C语言中,顺序的存储结构可以使用一个一维数组来存放中的元素,同时使用一个指示器top来指示顶的位置。在进行进和出操作时,需要更新top的值,使其指向顶元素。 下面是一种常见的顺序的定义和基本操作的示例代码: ```c // 定义中元素的数据类型 typedef int StackElementType; // 定义顺序的存储结构 #define Stack_Size 100 // 的最大容量 typedef struct { StackElementType elem[Stack_Size]; // 用数组存放中元素 int top; // 顶指针 } SeqStack; // 初始化顺序 void Init_SeqStack(SeqStack *S) { S->top = -1; // 初始时为空,顶指针置为-1 } // 进操作 void Push_SeqStack(SeqStack *S, StackElementType x) { if (S->top == Stack_Size - 1) { printf("已满,无法进"); return; } S->top++; // 顶指针加1 S->elem[S->top] = x; // 将新元素放入顶位置 } // 出操作 StackElementType Pop_SeqStack(SeqStack *S) { if (S->top == -1) { printf("为空,无法出"); return -1; // 返回一个特殊值表示出错 } StackElementType x = S->elem[S->top]; // 获取顶元素的值 S->top--; // 顶指针减1 return x; // 返回顶元素的值 } // 查看顶元素 StackElementType GetTop_SeqStack(SeqStack *S) { if (S->top == -1) { printf("为空"); return -1; // 返回一个特殊值表示出错 } return S->elem[S->top]; // 返回顶元素的值 } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值