数据结构:栈

一、线性表的操作增加约束条件
线性表元素和元素逻辑的逻辑关系1:1    插入  删除   可以在任意位置进行操作
    insertTable(Table *tab, int pos, Element e);
如果对插入  删除进行约束
    栈   :  只能在一端操作
        元素操作行为上: 先入后出(后入先出)
            羽毛球桶    子弹夹


    队列 :  只能在两端操作
栈的适应场景:
1. 用户场景: 

场景1:

像下图的迷宫(A是入口,F是出口),我们总是先向下,再向右,再向上,最后向左(穷举)。根据这个规律,A->B->C->G->H,发现走不通了,然后倒退到C,再到D->E->F(成功找到出口)。这个倒退的过程就要用到栈。

场景2:
    历史记录   ctrl+z 撤销(WPS,Word)   倒退

场景3:
    软件编程的时候,函数保护现场和恢复现场使用  
        局部变量  
            函数返回后,局部变量消失(不准确的说法)
        全局变量
            函数返回后,全局变量存在,程序退出后,彻底消失

例如,在执行fun1()函数第20行代码时,我们要调用abc()函数,但最终调用完之后要回到这里,我们必须记住这个位置(或者记录第21行的位置),等调用完之后继续执行21行,这里就需要用到栈。

2.操作行为:
   栈顶 top 可以加 也可以减
        先取元素  后取元素

栈的代码不用背,了解原理就可以根据前面的写出后面的。
4种栈:
    满栈  空栈          top指针指向的元素是  有效  和  待入栈  的位置
    递增  递减          入栈时,top是加++  减 --

例如空递增


C语言自动的(天然的)实现了一个栈:
    满递减栈

 

二、顺序存储栈的实现(容易栈溢出)
    满递增
Element data[MaxSize];
int top;

push   
    top++;
    data[top] = e;
pop
    *e = data[top];
    top--; 

三、链式存储栈的实现

栈只能在一段操作,所以我们需要维护一个指向某个节点的指针,这个指针一般就叫 node *top;

如上图所示,要插入一个新元素,我们先将新元素指向栈顶,然后更新top。
    newNode->next = top;
    top = newNode;
出栈:(备份思想)
    tmp = top;
    top = top->next;
    free(tmp);

四、代码实现:

由于顺序栈和链式栈写入一个文件,故先写一个头文件common.h来存放都要用的部分。

common.h


#ifndef COMMON_H
#define COMMON_H
#include<stdio.h>
#include<stdlib.h>
typedef int Element;
#endif //COMMON_H

顺序栈:

arrayStack.h

#ifndef ARRAYSTACK_H
#define ARRAYSTACK_H
/* 顺序栈 满递增栈*/
#define MaxStackSize 5 //宏定义栈大小
#include "common.h"
typedef struct {
	Element data[MaxStackSize];
	int top;
}ArrayStack;
//申请栈
ArrayStack *createArrayStack();
//释放栈
void releaseArrayStack(ArrayStack *stack);
//压栈push(把哪个元素e压入哪个栈stack)
int pushArrayStack(ArrayStack *stack, Element e);
//出栈pop
int popArrayStack(ArrayStack *stack, Element *e);

#endif //ARRAYSTACK_H

arrayStack.c

#include <stdlib.h>
#include <stdio.h>
#include "arrayStack.h"
/* 顺序栈 满递增栈*/
ArrayStack *createArrayStack() {
	ArrayStack *stack = (ArrayStack *) malloc(sizeof(ArrayStack));
	if (stack == NULL) {
		printf("malloc failed\n");
		return NULL;
	}
	stack->top = -1;//因为是满栈,初始化为-1.如果是空栈,初始化为0.
	return stack;
}

/* 数据能存放的位置 : [0, 1, ... max-1] */
int pushArrayStack(ArrayStack *stack, Element e) {
	// 上溢出(overflow)的问题排除
	if (stack->top >= MaxStackSize - 1) { //判断条件也可以写成stack->top+1 >MaxStackSize - 1
		printf("OverFlow\n");
		return -1;
	}
	stack->data[++stack->top] = e;//等价于stack->top++; stack->data[stack->top]=e;
	return 0;
}

int popArrayStack(ArrayStack *stack, Element *e) {
	if (stack->top < 0) {
		printf("UnderFlow!\n");
		return -1;
	}
	*e = stack->data[stack->top--];//等价于*e = stack->data[stack->top]; top--;
	return 0;
}

void releaseArrayStack(ArrayStack *stack) {
	if (stack) {
		free(stack);
	}
}

链栈:

linkStack.h


#ifndef LINKSTACK_H
#define LINKSTACK_H
/* 链式存储栈,关注节点结构,栈的操作结构 */
#include "common.h"
// 节点结构
typedef struct stackNode {
	Element e;
	struct stackNode *next;
}StackNode;
// 链式栈的表头结构
typedef struct {
	StackNode *top;          //栈顶
	int count;				// 统计栈里的元素
}LinkStack;

LinkStack *createLinkStack();
void releaseLinkStack(LinkStack *stack);

int pushLinkStack(LinkStack *stack, Element e);
int popLinkStack(LinkStack *stack, Element *e);


#endif //LINKSTACK_H

linkStack.c


#include "linkStack.h"
LinkStack *createLinkStack() {
	LinkStack *stack = (LinkStack *) malloc(sizeof(LinkStack));//申请表头
	if (stack == NULL) {
		printf("malloc failed!\n");
		return NULL;
	}
	stack->top = NULL;    //刚开始没元素,为空
	stack->count = 0;     //
	return stack;
}

int pushLinkStack(LinkStack *stack, Element e) {
	StackNode *node = (StackNode *) malloc(sizeof(StackNode));//申请栈空间
	if (node == NULL) {
		printf(".....!\n");
		return -1;
	}
	node->e = e;
	node->next = stack->top;
	stack->top = node;
	stack->count++;
	return 0;
}

int popLinkStack(LinkStack *stack, Element *e) {
	if (stack->top == NULL) {
		printf(",,,,,,,,\n");
		return -1;
	}
	*e = stack->top->e;
	//利用备份思想
	StackNode *tmp = stack->top;
	stack->top = tmp->next;
	free(tmp);
	stack->count--;
	return 0;
}

void releaseLinkStack(LinkStack *stack) {
	if (stack) {
		// 以top指向的元素逐个删除,top为空时停止
		while (stack->top) {
			StackNode *tmp = stack->top;
			stack->top = tmp->next;
			free(tmp);
			stack->count--;
		}
		printf("stack count : %d\n", stack->count);
		//所有节点释放完之后,释放表头
		free(stack);
	}
}


main.c来测试结果

顺序栈和链栈的测试结果用===============划分

#include <stdio.h>
#include "arrayStack.h"
#include "linkStack.h"
/*顺序栈的测试*/
int test01() {
	ArrayStack *stack = createArrayStack();
	Element e;
	if (stack == NULL) {
		return -1;
	}
	//压五个入栈[100,101,...104]
	for (int i = 0; i < 5; ++i) {
		pushArrayStack(stack, i + 100);
	}
	//再压会溢出
	pushArrayStack(stack, 500);
	printf("pop:");
	for (int i = 0; i < 5; ++i) {
		popArrayStack(stack, &e);
		printf("\t%d", e);
	}
	printf("\n");
	popArrayStack(stack, &e);
	releaseArrayStack(stack);
	return 0;
}
/* 链式栈的测试 */
int test02() {
	LinkStack *stack = createLinkStack();
	Element e;
	if (stack == NULL) {
		return -1;
	}
	//压入5个
	for (int i = 0; i < 5; ++i) {
		pushLinkStack(stack, i + 50);
	}
	printf("stack node: %d\n", stack->count);
	printf("pop:");
	//弹出5个
	for (int i = 0; i < 5; ++i) {
		popLinkStack(stack, &e);
		printf("\t%d", e);
	}
	printf("\n");
	popLinkStack(stack, &e);//已经弹完了,再弹会报错
	releaseLinkStack(stack);
	return 0;
}

int main() {
	test01();
	printf("=================\n");
	test02();
	return 0;
}

在CLion上运行结果如下:

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值