数据结构——栈

何为栈

栈(stack)是只允许在一段进行插入和删除数据的操作的线性表。所以栈是一种操作受限的线性表。栈中有一下三个概念。

栈顶(Top):线性表允许进行操作的那一端(插入、删除)
栈底(Bottom):固定的,不允许进行操作的一端
空栈:不含任何元素的空表
压栈:向栈中插入数据
出栈:删除栈顶数据

栈的操作就像一个箱子,我们放入数据的时候只能层层堆叠,取数据的时候只能从最上面的数据开始。这种栈的操作特性可以简单的概括为后进先出(Last In First Out)
所以对于栈来讲:他属于线性表,所以逻辑结构依然是线性结构,当然存储结构也可以使用顺序存储和链式存储。
栈的数学性质: n各不同元素进栈,出栈元素不同排列个数为 1 n + 1 C 2 n n \frac{1}{n+1}C_{2n}^n n+11C2nn

栈的顺序存储

采用顺序存储的栈也成为顺序栈,类似于顺序表,,使用一块连续的存储单元存放数据,并设置一个指针(top),指示当前栈顶元素。

顺序栈的实现

#include<stdio.h>
#include<stdlib.h>

typedef struct stack{
	int *data;    			// 数据区域
	int size, top, cmp;      //size 栈大小    top栈顶指针     cmp栈容量大小
}stack;

其实我们不需要设置size,top本可很好的表示,但是为了观察和解释方便设置了size,如果是静态的话,我们也不需要设置cmp,我们实现的是动态的。所以在我的实现中,为了避免功能重复,top我就直接变成了栈顶数据。


stack *initStack(int cmp){
	stack *s = (stack *)malloc(sizeof(stack));
	s->data = (int *)malloc(sizeof(int) * cmp);
	s->cmp = cmp;
	s->size = 0;
	s->top = -1;
	return s;
}

void deleteStack(stack *s){
	free(s->data);
	free(s);
}

首先依旧是初始化工作和销毁工作,当然销毁的时候,为了避免内存泄漏要先释放数据区,然后释放栈。


void getTop(stack *s){
	printf("the top :%d\n",s->top);	
}

void pushStack(stack *s, int val){
	if(s->size == s->cmp){
		s->cmp *= 2;
		s->data = (int *)realloc(s->data, sizeof(int) * s->cmp); 
		printf("exp!\n");
	}	
	s->data[s->size] = val;
	s->top = s->data[s->size];
	s->size++;
}

int top(stack *s){
	if(s->size == 0){
		s->top = -1;
		return 0;
	}
	s->size--;
	s->top = s->data[s->size - 1];
	return 1;
}

在这里呢我只实现了三个栈操作,查看栈顶元素,压栈和出栈,因为我们数据区是动态的所以需要考虑扩容的工作,但是基于栈的性质,扩容工作很好实现(在循环队列的时候就会比较麻烦)。


void showStack(stack *s){
	int a = s->size;
	while(a--){
		printf("%d ",s->data[a]);
	}
	printf("\n");
}

当然在最好还要再写一个输出功能来检验我们的实现成果


int main(){
	stack *s = initStack(3);
	int a,val;
	while(1){
		scanf("%d", &a);
	if(a == 1){
		scanf("%d",&val);
		pushStack(s ,val );
	}
	else if(a == 2){
		top(s);
	}
	else if(a == 3){
		getTop(s);
		continue;
	}
	else{
		deleteStack(s);
	}
	showStack(s);
	printf("---------------------------------------------\n");
	}
	return 0;
}

主函数部分,进行测试。测试结果如下
在这里插入图片描述
这样就基本实现了顺序栈的功能。

共享栈

可以看到栈的特点是,栈顶始终不变,栈顶进行插入和弹出,如果我们开辟了一个很大的一位数组空间,但是如果栈的大小很小的话,那么就造成了资源浪费。所以这个时候我么可以让两个栈公用一片空间,基于栈的特性。一个栈底设在数组低位0,一个栈底设在数组高位array_max。两个栈顶往中间延伸,可以更充分的利用资源空间。
当然,当两个栈的栈顶指针满足 t o p 1 − t o p 2 = 1 top_1 -top_2 = 1 top1top2=1的时候,就是栈满的情况。可能发生数据上溢。但是对于两个栈的存取没有任何影响。

栈的链式存储结构

采用链式存储结构的栈称为链栈,相较于顺序栈,链栈的优点就是有多个栈共享存储空间和提高其效率,且不存在栈满上溢的情况,通常用单链表实现。

#include<stdio.h>
#include<stdlib.h>

typedef struct node{		//节点
	int val;
	node *next;
}node;

typedef struct stack{		//栈
	node *head;
	int size, top;
}stack;

node *newNode(int val){			//创建新节点的方法
	node *n = (node *)malloc(sizeof(node));
	n->val = val;
	n->next = NULL;
	return n; 
}

相较于顺序栈功能并无变动,只是随着存储结构的改变进行的调整,但思路一致

stack *initStack(){								//初始化栈
	stack *s = (stack *)malloc(sizeof(stack));
	s->head = (node *)malloc(sizeof(node));
	s->head->val = -1;
	s->head->next = NULL;
	s->size = 0;
	s->top = 0;
	return s;
}

void deleteStack(stack *s){					//销毁栈
	node *t1 = s->head;
	while(t1){
		node *t2 = t1->next;
		free(t1);
		t1 = t2;
	}
	free(s);
}

int getTop(stack *s){				//获取栈顶元素
	printf("%d\n",s->top);
	return s->top;
}

void pushStack(stack *s, int val){   //压栈
	node *n = newNode(val);
	n->next = s->head->next;
	s->head->next = n;
	s->size++;
	s->top = s->head->next->val;
}

void top(stack *s){					//出栈
	node *n;
	n = s->head->next;
	s->head->next = s->head->next->next;
	s->top = s->head->next->val;
	free(n);
}

void showStack(stack *s){ 			//输出栈
	node *n = s->head;
	while(n->next){
		n = n->next;
		printf("%d ", n->val);
	}
	printf("\n");
}

同样是初始化,删除,压栈,出栈,查看栈顶元素以及输出栈的五种方法,还是需要注意的是,因为数据是以链式结构存储,所以在销毁栈之前需要遍历释放节点再释放栈。

int main(){
	stack *s = initStack();
	int a,val;
	while(1){
		scanf("%d", &a);
	if(a == 1){
		scanf("%d",&val);
		pushStack(s ,val );
		showStack(s);
	}
	else if(a == 2){
		top(s);
		showStack(s);
	}
	else if(a == 3){
		getTop(s);
	}
	
	else{
		deleteStack(s);
	}
	printf("---------------------------------------------\n");
	}
	return 0;
}

主函数运行,查看运行结果
在这里插入图片描述

小结

栈是一种操作受限制的线性表,所以他的逻辑结构依然是线性。
所以也有链式和顺序两种存储结构
顺序栈中有一个特殊的栈就是共享栈,一块连续的空间存放两个,栈底分别放在高位和低位
链栈相较于顺序栈的最大有点就是不会出现栈满上溢的情况
栈有一些基本操作,初始化栈,销毁栈,入栈、出栈、获取栈顶、判断栈孔空等
栈只能通过栈顶进行数据增加和删除,所以栈的最大特点就是LIFO后进先出。
另外栈有一个数学性质:就是n个元素进栈,出栈元素不同排列的个数为 1 n + 1 C 2 n n \frac{1}{n+1}C_{2n}^n n+11C2nn删除线格式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值