堆栈与单调栈

进栈和出栈的示意图

当元素进栈时,栈顶指针指向第一个为空的元素地址。

当元素出栈时,栈顶指针向下移动一个存储单元

//栈的类型定义
typedef  int  ElemType ;
typedef struct stack
{   
      ElemType  *bottom;   //栈底指针 
      ElemType  *top;      //栈顶指针 
      int   stacksize ;       //当前栈的容量 
}Stack ;

/*栈的初始化
假设初始时给栈分配存储空间大小为STACK_SIZE,栈的容量也赋值为STACK_SIZE。
栈初始化算法的主要过程:
1)为栈分配存储空间(也就是给栈底指针分配空间,这是因为栈底是固定不动的);
2)让栈顶指针指向栈底(表示栈是空的)。*/
Status Init_Stack( Stack  &S  )
{
	S.bottom=(ElemType *)malloc(STACK_SIZE *sizeof(ElemType));
	if ( !S.bottom ) //判断分配空间是否成功,如果失败则返回错误
	      return  ERROR;
	S.top = S.bottom ;    //初始化时让栈顶指针指向栈底
	S. stacksize = STACK_SIZE; //初始化时
	return OK ;
}//Init_Stack

/*进栈(也称压栈、入栈)
元素进栈算法的主要过程:
1)首先判断栈的容量是否已经达到最大,如果达到,则追加存储空间,并重新定位栈顶指针的位置(其实就是指向实际的栈顶),然后更新栈的容量;
2)把入栈元素存入栈顶;
3)栈顶指针指向新栈顶。*/
Status Push(Stack &S , ElemType  e)
{
	//如果栈满,则使用realloc追加存储空间
	if( S.top-S.bottom >= S. stacksize-1 )      
    {
		S.bottom=(ElemType *)realloc( S.bottom, (S.stacksize+STACK_SIZE) * sizeof(ElemType));  
        if( !S.bottom )//如果重新分配存储空间失败,则返回错误     
            return  ERROR; 
		S.top = S.bottom + S.stacksize;//重新定位栈顶 
		S.stacksize += STACKINCREMENT;//更新栈的容量 
	}
	*S.top = e;//把元素存入栈顶  
	S.top++; //栈顶指针加1(即向上移动一个存储单元),e成为新的栈顶   
	return OK;
}//Push

/*出栈(也称弹栈)
元素出栈算法的主要过程:
1)判断栈是否是控制,如果是则返回出栈失败;
2)栈顶指针下移一个存储单元;
3)把栈顶指针指向位置的元素存入到目标变量中*/
Status Pop( Stack  &S, ElemType  &e )      
{   
	if( S.top == S.bottom ) //栈空,返回失败  
		return ERROR ;  
	S.top--;//栈顶下移
	e = *S.top;//用e缓存栈顶元素
	return  OK; 
}// Pop 

/*取栈顶元素
取栈顶元素的主要步骤:
1)判断栈是否为空,为空则返回失败
2)取栈顶元素并存储到相应的变量中,需要注意的是栈顶元素实际存储在栈顶指针的下一个存储空间中。*/
Status GetTopElement( Stack S, ElemType  &e )      
{   
	if ( S.top == S.bottom ) //如果栈为空,则返回失败
		return ERROR ;       
	e = *(S. top – 1) ;      //用e缓存栈顶元素
	return  OK ; 
}//GetTopElement

/*把栈置为空栈
把栈置为空栈的主要步骤:
1)把栈顶指针指向栈底即可。*/
Status ClearStack( Stack &S )
{   
	S.top = S.bottom; 
	return  OK ; 
}// ClearStack

/*销毁栈
销毁栈的主要步骤:
1)释放栈底指针(因为栈的存储空间是通过给栈底指针分配空间得到的)
2)把栈底指针和栈顶指针均赋值为NULL
3)把栈的容量赋值为0*/
Status DestroyStack( Stack &S )      
{   
	free( S.bottom );
	S.top =  NULL;
	S.bottom  = NULL;
	S. stacksize = 0;
	return  OK ; 
}// DestroyStack

链栈与链栈的应用

链栈的基本操作

注:

1.链栈不需要设置头结点,因为链栈的插入和删除元素都在只能在栈顶操作。

2.栈分外部结构和内部结构,外部结构是指栈顶指针top;内部结构是指栈的结点环环相扣,链栈的内部结构类似于单链表,但next的指向方向不同,链栈是由栈顶指向栈底,即从后往前指,而单链表是从前往后指,注意区别!

3. 在链栈出栈操作中,需注意要存放出栈元素,须先在主函数定义一个dataType类型的变量elem(注意是“ 变量 ”而不是 “ 指针变量 ”),然后调用出栈函数时将elem的地址传给形参,即pop_out(&s,&elem),通过变量地址传入函数间接访问的方式,才能成功的用elem存取出栈元素的值。

//链栈的实现及功能
#include<stdio.h>
#include<stdlib.h>

typedef int datatype;

//栈的内部结构,即栈的结点
typedef struct node
{
	datatype data;
	struct node *next;
}stacknode;

//栈的外部结构
typedef struct stack
{
	stacknode *top;//栈顶指针
	int length;//栈的节点数(元素个数)
}linkstack;

//[1]栈的初始化,初始化外部结构即可
void initalize(linkstack **s)
{
	(*s)->top=NULL;//栈顶指针置空,注意*s要加括号
	(*s)->length=0;//栈顶元素初始值为0,节点数也为0
}

//[2]入栈,链栈与顺序栈不同,链栈入栈不需要判栈满
void push(linkstack **s,datatype value)
{
	//对内部结构的操作(先)
	stacknode *p;
	p=(stacknode*)malloc(sizeof(stacknode));
	p->data=value;
	p->next=(*s)->top;//这里注意:链栈中next的指向与链表中next的指向不同,链栈由栈顶指向栈底,即由后往前指。而链表是由前往后指
	//对外部结构的操作(后)
	(*s)->top=p;
	(*s)->length++;
	
}

//[3]出栈,需判断栈是否为空
void popout(linkstack **s,datatype *value)
{
	stacknode *p;
	if((*s)->length==0){
		printf("此链栈为空");
		return;
	}
	p=(*s)->top;
	*value=(*s)->top->data;//此步骤是用于存放出栈的元素,注意事项见注3
	(*s)->top=p->next;
	(*s)->length--;
	printf("pop element is %d\n",*value);
}

//[4]得到栈顶元素
datatype gettop(linkstack *s)
{
	if(s->length==0)
		printf("linkstack is empty\n");
	else
		return(s->top->data);
}

//[5]栈的遍历及输出
void traverse(linkstack *s)
{
	stacknode *p;
	int i;
	if(s->length==0){
		printf("linkstack is empty\n");
		return;
	}
	p=s->top;
	printf("the elements in the stack are:");
	for(i=0;i<s->length;i++){
		printf("%d->",p->data);//从栈顶指向栈底部
		p=p->next;
	}
	printf("stack base\n");
}

int main()
{
	linkstack *s;
	datatype value;
	initalize(&s);
	push(&s,10);
	push(&s,10);
	push(&s,10);
	push(&s,10);
	popout(&s,&value);
	traverse(s);
	

	return 0;
}


栈的应用

1:进制转换

算法:假如N为输入的数,n为要转换为的进制,若要将十进制231转换为8进制数,过程如下;

N                        N/n                      N%n

231                   28                         7

28                      3                           4

3                        0                           3

则输出为347,可以看出,首先得到的应该是7,然后才是4,最后是3,但是要逆序显示,自然就类似压栈出栈的数据结构了(数组也可以实现,但是没有体现其本质).

所以,只需要初始化栈后,将N%n不断的压入栈底,需要注意的是如果要转换为16进制,则需要对大于9的数字作字符处理。

这里提一下realloc函数

1.realloc函数会将原有空间的数据拷贝到新的空间

2.realloc函数会释放原有空间的内存

3.底层使用malloc函数实现malloc函数

申请新空间,并且需要手动移动数据,释放原有空间

//利用栈实现进制转换
#include<stdio.h>
#include<malloc.h>
#include<String.h>
#define STACKSIZE 100
#define STACKINCREMENT 10
typedef int Status;
typedef int Etype;
typedef struct stack
{   
	Etype  *bottom;   //栈底指针 
	Etype  *top;      //栈顶指针 
	int    stacksize; //当前栈的容量 
}Stack; 

Status InitStack( Stack &S );//初始化
Status Push( Stack &S , Etype e );//压栈
Status Pop( Stack  &S, Etype  &e );//弹栈
void BaseConversion( unsigned n, unsigned base );

int main()
{
	unsigned n, base;
	printf( "请输入一个十进制整数: " );
	scanf( "%ud", &n );//无符号类型的整形,打印时用%ud 
	printf( "你想将他转为几进制: " );
	scanf( "%ud", &base );
	printf( "结果: " );
	BaseConversion( n, base );
}

//栈的初始化 
Status InitStack( Stack &S )
{
	S.bottom=(Etype *)malloc(STACKSIZE *sizeof(Etype));
	if ( !S.bottom ) //判断分配空间是否成功,如果失败则返回错误
	{
		return  0;
	}
	S.top = S.bottom ;    //初始化时让栈顶指针指向栈底
	S.stacksize = STACKSIZE; //初始化时
	return 1 ;
}

//压栈(进栈、入栈) 
Status Push( Stack &S , Etype e )
{
	//如果栈满,则使用realloc追加存储空间
	if( S.top - S.bottom >= S.stacksize-1 )      
	{
		S.bottom=(Etype *)realloc( S.bottom, (S.stacksize+STACKSIZE) * sizeof(Etype) );  
		if( !S.bottom )//如果重新分配存储空间失败,则返回错误     
		{
			return  0; 
		}
		S.top = S.bottom + S.stacksize;//重新定位栈顶 
		S.stacksize += STACKINCREMENT;//更新栈的容量 
	}
	*S.top = e;//把元素存入栈顶  
	S.top++; //栈顶指针加1(即向上移动一个存储单元),e成为新的栈顶   
	return 1;
}//Push

Status Pop( Stack  &S, Etype  &e )      
{   
	if( S.top == S.bottom ) //栈空,返回失败  
	{
		return 0; 
	}	
	S.top--;   //栈顶下移
	e = *S.top;//用e缓存栈顶元素
	return 1; 
}// Pop 

void BaseConversion( unsigned n, unsigned base ) 
{
	Stack S;
	int k, e;
	InitStack( S );
	while( n > 0 )
	{
		k = n % base;
		Push( S, k );
		n = n / base;
	}
	while( S.top != S.bottom )
	{
		Pop( S, e );
		char format[3]={ '%' };
		if( base == 16 ) 
		{
			format[1] = 'x';
		}
		else
		{
			format[1] = 'u';
		}
		printf( format, e );
	}
	free( S.bottom );
}

2:判断括号是否匹配

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<string.h>
#define MaxSize 100

typedef struct {
	char data[MaxSize];
	int top;
}SqStack;

//初始化栈
void InitStack(SqStack *S) {
	S->top = -1;
}
//判栈空
bool IsEmpty(SqStack S) {
	if (S.top == -1) {
		return true;
	}
	else {
		return false;
	}
}
//入栈
void Push(SqStack *S, char x) {
	if (S->top == MaxSize-1) {
		printf("栈已满");
		return;
	}
	S->top += 1;
	S->data[S->top] = x;
}
//栈顶元素出栈,用x返回
void Pop(SqStack *S, char *x) {
	if (S->top == -1) {
		printf("栈已满");
		return;
	}
	*x = S->data[S->top];
	S->top -= 1;   //S->top=S->top+1;
}
//匹配算法
bool bracketCheck(char str[], int length) {
	SqStack S;
	InitStack(&S);//初始化
	for (int i = 0; i < length; i++) {
		if (str[i] == '(' || str[i] == '[' || str[i] == '{') {
			Push(&S, str[i]);//扫描到左括号就进栈
		}
		else {
			if (IsEmpty(S)) { //扫描到右括号,栈空
				return false;//匹配失败
			}
			char topElem;//保存弹出的栈顶元素
			Pop(&S, &topElem);//栈顶元素出栈
			if (str[i] == ')' && topElem != '(') {
				return false;
			}
			if (str[i] == '}' && topElem != '{') {
				return false;
			}
			if (str[i] == ']' && topElem != '[') {
				return false;
			}
		}
	}
	return IsEmpty(S);
}
int main() {
	char c[MaxSize];
	printf("请输入需要判断的括号:");
	scanf("%s", c);
	int len = strlen(c);
	printf("当前输入括号的个数为:%d", len);
	printf("现在开始判断...");
	if (bracketCheck(c, len)) {
		printf("匹配成功!");
	}
	else {
		printf("匹配失败!");
	}
	return 0;
}


3:栈判断回文字符串

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值