考研二战_数据结构_day6_顺序栈+链栈

目录

前言

一、栈的基本概念

二、栈的顺序存储

1、初始化

2、判空

3、入栈

4、出栈

5、获取栈顶元素

6、优缺点

7、测试

三、共享栈

四、栈的链式存储

1、初始化

2、判空

3、入栈

4、出栈

5、取栈顶元素

6、测试

后记


前言

        有一说一,昨天学的确实少。今天看了看栈的内容,发现有一个问题,栈用顺序存储的形式实现比较简单,用链式存储来实现有点麻烦。当时学习的时候,我认为栈的链式存储方式和单链表一样,就没有去细想,现在仔细想想还是有不一样的地方。

        比如头节点的指针最好是prior指针,这样方便进行出入栈的操作。这是我还没有实现时的想法,等等我再去找点资料好好复习复习。


一、栈的基本概念

        栈 (Stack) 只允许在一端进行插入和删除操作线性表

        基本特点是先进后出(FILO),例如电梯

        术语:栈底、栈顶、空栈

        1、栈底:不允许进行操作的一端

        2、栈顶:允许进行操作的一端

        3、空栈:栈中无元素

 

二、栈的顺序存储

1、初始化

        此处比较简单,由于顺序栈与顺序表不一样,顺序栈没有位序的概念,只有栈顶与栈底的概念,所以顺序栈中第一个元素一般记为0,而不是1,所以在初始化时需要注意top的值。

        不过也可以与顺序表相对应,将第一个元素记为1,但需要注意其在数组中的下标为0。

typedef int ElemType;

#define MaxSize 10

typedef struct {
	ElemType data[MaxSize];
	int top;  //指向栈顶
} SqStack;

//初始化顺序栈
bool InitSqStack(SqStack &stack) {
	stack.top = -1;  //top记为 -1 表示栈顶为空

	return true;
}

int main() {
	SqStack stack;
	if(InitSqStack(stack)) printf("Initial Success!\ntop = %d\n", stack.top);

	return 0;
}

2、判空

        判断是否为空可以用top来判断,需要考虑初始化时top的赋值。此处top == -1 时表示栈空。

//判断顺序栈是否为空
//初始化时top=-1
bool isEmpty(SqStack stack) {
	if(stack.top == -1) return true;
	else return false;
}

3、入栈

        当栈不满时才可以添加,只能在栈顶除添加。

//入栈,在顺序栈stack中添加数据元素elem
bool Push(SqStack &stack, ElemType elem) {
	if(stack.top >= MaxSize-1) return false;  //栈满,无法插入

	stack.top += 1;                //将top指向第一位元素存放位置(此处top起始为-1)
	stack.data[stack.top] = elem;  //赋值

	return true;
}

4、出栈

        当栈不为空时才能出栈,并获取该元素。

//出栈,将栈顶元素记录在elem中
bool Pop(SqStack &stack, ElemType &elem) {
	if(isEmpty(stack)) return false;  //栈空,无栈顶元素

	elem = stack.data[stack.top];  //存储
	stack.top -= 1;                //top下移一位

	return true;
}

5、获取栈顶元素

        出栈时怎么获取栈顶元素,这边就怎么获取

//读栈顶元素
bool getTop(SqStack stack, ElemType &elem) {
	if(isEmpty(stack)) return false;  //栈空,无栈顶元素

	elem = stack.data[stack.top];  //存储

	return true
}

6、优缺点

        优缺点与顺序表的优缺点一样。

7、测试

int main() {
	SqStack stack;
	ElemType elem;

	if(InitSqStack(stack)) printf("Initial Success!\n\n");
	if(isEmpty(stack)) printf("Stack is Empty!\n\n");

	for(int i = 0; i<6; i++) {
		ElemType temp = rand() % 10 + 1;  //生成一个1~10的数
		if(Push(stack, temp)) printf("Push %d Success! top = %d\n", temp, stack.top);
		else printf("Push %d Fail! top = %d\n", temp, stack.top);
	}
	puts("");

	if(Pop(stack, elem)) printf("Pop %d Success! top = %d\n\n", elem, stack.top);
	else  printf("Pop Fail! top = %d\n\n", stack.top);
	
	if(getTop(stack, elem)) printf("Get Top Data %d Success! top = %d\n", elem, stack.top);
	else printf("Get Top Data Fail! top = %d\n", stack.top);

	return 0;
}

三、共享栈

        两个栈共用一个存储空间。

        初始化时,top0 = -1,top1 = MaxSize,判满则是top0 + 1 == top1


四、栈的链式存储

        我的构想如图。话说,如果只有一个指针,是否用next更好?

1、初始化

        与单链表一样,初始化分为带头节点的初始化与不带头节点的初始化。两种初始化都行,我个人倾向于使用不带头节点的初始化方法。

typedef int ElemType;

#define MaxSize 10

typedef struct StackNode {
	ElemType data;
	struct StackNode *prior;
} LNode, *LinkStack;

//带头节点的初始化
bool InitStack_Test(LinkStack &stack){
	stack = (LNode*)malloc(sizeof(LNode));
	if(stack == NULL) return false;  //声明空间出错
	
	stack->prior = NULL;  //头节点指向NULL 
	
	return true;
} 

//不带头节点的初始化
//stack指向的时链栈的栈顶,即top
bool InitStack(LinkStack &stack) {
	stack = NULL;  //初始指向NULL

	return true;
}

2、判空

        由于我用的是不带头节点的初始化,所以当栈顶指针stack指向NULL时,该链栈为空。

//判空
bool isEmpty(LinkStack stack) {
	if(stack) return false;  //stack不指向NULL

	return true;
}

3、入栈

        入栈比较简单,在插入新节点后,将栈顶指针stack指向该节点即可。

//入栈,数据元素为elem 
bool Push(LinkStack &stack, ElemType elem) {
	LNode* node = (LNode*)malloc(sizeof(LNode));
	if(node == NULL) return false;  //声明空间失败

	node->data = elem;    //赋值
	node->prior = stack;  //将stack指向的节点变为node的前驱
	stack = node;         //将stack指向node指向的节点

	return true;
}

4、出栈

        注意要用free函数释放空间

//出栈,将栈顶元素存到elem中 
bool Pop(LinkStack &stack, ElemType &elem) {
	if(isEmpty(stack)) return false;  //栈空,无栈顶元素
	LNode* node = stack;  //node指向stack的栈顶

	elem = node->data;    //转移数据 
	stack = node->prior;  //stack向前移 

	free(node);           //释放栈顶节点 

	return true;
}

5、取栈顶元素

        出栈怎么转移元素,这边就怎么取元素

//取栈顶元素,存到elem中 
bool getTop(LinkStack stack, ElemType &elem) {
	if(isEmpty(stack)) return false;  //栈空,无栈顶元素

	elem = stack->data;  //转移元素

	return true;
}

6、测试

void PrintStack(LinkStack stack) {
	while(stack) {
		printf("%d ", stack->data);
		stack = stack->prior;
	}
	puts("\n");
}

int main() {
	LinkStack stack;  //测试用链栈
	ElemType elem;    //测试用数据元素

	if(InitStack(stack)) printf("Initial Success!\n\n");

	for(int i = 0; i<6; i++) {
		ElemType temp = rand() % 10 + 1;  //生成一个1~10的数
		if(Push(stack, temp)) printf("Push %d Success!\n", temp);
		else printf("Push %d Fail!\n", temp);
	}
	PrintStack(stack);

	if(Pop(stack, elem)) printf("Pop %d Success!\n", elem);
	else printf("Pop Fail!\n");
	PrintStack(stack);

	if(getTop(stack, elem)) printf("Get Top Data %d Success!\n", elem);
	else printf("Get Top Data Fail!\n");

	return 0;
}


后记

        光顾着敲代码了,没有写上自己的感悟。我觉得自己对于指针的使用已经掌握了一些皮毛了,指针只是一个定位器,指向的是地址、是空间。对指针进行操作,就是对那个空间进行操作。

        所以操作指针就是操作空间。使用指针时,不要只想着节点中的数据;而是要想着节点所在的空间,然后才是空间中存储数据元素的那块空间中的数据。

        明天就是队列的相关知识,有普通队列,有循环队列,可以用顺序存储的形式,也能用链式存储的形式。应该是比较好实现的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值