赞
踩
栈是一种先入后出(或是后入先出)的结构,通常插入和删除操作的一端称为栈顶,另一端称为栈底。
栈的结构也是线性表的一种,结构实现一般可以用数组或者链表实现,相对而言数组的结构实现更优一点。因为数组在尾上插入数据的代价比较小。
结构选择以及思路:
如果用数组栈的话:可以通过malloc一个动态空间,创建一个指针指向这个空间,为了判断空间的容量情况,可以通过创建一个top记录有效数据数量,一个capacity记录空间最大容量。
如果用链式栈的话:如果用尾做栈顶,尾插尾删,如果不设计成双向链表,每次尾删都需要遍历找尾,很麻烦。如果用头做栈顶的话,头插头删,这样就可以设计较方便的单链表。
其实在系统中的内存有一部分被划分的内存区域也被称为 栈,函数的栈帧就是在这一块区域内开辟,所以一些临时变量也储存在这个区域。栈中,空间使用自上而下(由高地址到低地址),并且栈很小,一般8M。
而本章的数据结构中的栈,它是我们通过在系统内存中的堆区进行模拟实现出来的,它随着程序结束而销毁。堆存储着我们用动态内存开辟的变量,空间总体由下而上(但并不是一定上一个地址低于下一个,可能使用后又销毁),堆区很大,一般以G为单位。
正因为堆区很大,栈区很小,所以当一些使用递归的算法递归太深出现栈溢出,并且不好使用迭代进行实现的时候,可以通过在堆区模拟栈,从而实现算法。
头文件:Stack.h
//Stack.h #include<stdio.h>; #include<stdlib.h>; #include<assert.h>; //断言所需要调的库 #include<stdbool.h>;//布尔型调用的库 typedef int STDataType; typedef struct stack { STDataType* a;//动态空间指针 int top; int capacity; }ST; //所需要实现的函数 //初始化栈 void StackInit(ST*ps); //销毁栈 void StackDestroy(ST* ps); //入栈 void StackPush(ST* ps, STDataType x); //出栈 void StackPop(ST* ps); //返回栈顶元素 STDataType StackTop(ST* ps); //栈的有效数据个数 int StackSize(ST* ps); //判断栈是否为空 bool StackEmpty(ST* ps);
测试页:Test.c
//Test.c
#include"Stack.h"
void StackTest1() {
ST st;//定义结构体变量
StackInit(&st);
StackPush(&st, 1);
//以下可以自己调用测试
...
}
int main(){
StackTest1();
return 0;
}
数组栈用动态顺序表这种更优的方式实现。
接下来的函数操作在源文件Stack.c中实现。
//Stack.c
//栈的初始化
#include"Stack.h"
void StackInit(ST* ps) {
ps->a = NULL;
ps->capacity = 0;
ps->top = 0;//或者-1
}
先将结构体ST中的值先初始化,为了接下来的操作观察更方便。
//Stack.c
//栈的销毁
void StackDestroy(ST* ps) {
free(ps->a); //释放a指针指向的空间
ps->a = NULL;
ps->capacity = ps->top = 0;//一切回归初始
}
//Stack.c //入栈操作 void StackPush(ST* ps, STDataType x) { if (ps->capacity == ps->top) { //先判断 有效数据数是否等于最大容量 int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;//建立新的容量变量 STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newcapacity);//用realloc 扩建空间大小 if (tmp == NULL) { printf("realloc fail\n"); exit(-1); } ps->a = tmp; //赋值给结构体中的 ps->capacity = newcapacity; } ps->a[ps->top++] = x; //赋值入栈 top++ }
//Stack.c
//出栈操作
void StackPop(ST* ps) {
/*assert(ps->top > 0);*/
assert(!StackEmpty(ps));//如果为不为空程序继续,否则报错。
ps->top--;//先进先出 直接--
}
//Stack.c
//判空操作
bool StackEmpty(ST* ps) {
return ps->top==0; //说明栈里的有效数据数为0,栈为空
}
//Stack.c
//取栈顶数据操作
STDataType StackTop(ST* ps) {
assert(!StackEmpty(ps)); //为空报错
return ps->a[ps->top-1];//因为每次在给top位置赋值后,top会++
}
//Stack.c
//取栈有效数据数
int StackSize(ST* ps) {
return ps->top; //就是top的数
}
如果用头做栈顶,头插头删,这样就可以设计较方便的单链表。
头文件:SLStack.h
//STStack.h #pragma once #include<stdio.h> #include<assert.h> #include<stdlib.h> #include<stdbool.h> typedef int SDataType; typedef struct stack { struct stack* next; SDataType data; }ST; void StackPush(ST** top,SDataType x); void StackPop(ST** top); SDataType StackTop(ST** top); int StackSize(ST** top); bool StackEmpty(ST** top); void StackDestroy(ST** top);
测试页:SLTest.c
#include"SLStack.h" void Test1() { ST* ps=NULL; StackPush(&ps, 1); printf("%d", StackTop(&ps)); StackPush(&ps, 2); printf("%d", StackTop(&ps)); StackPush(&ps, 3); printf("%d", StackTop(&ps)); StackPush(&ps, 4); printf("%d\n", StackTop(&ps)); printf("%d\n", StackSize(&ps)); while (!StackEmpty(&ps)) { printf("%d", StackTop(&ps)); StackPop(&ps); } StackDestroy(&ps); } int main() { Test1(); return 0; }
先创建单个结点
//SLStack.c
#include"SLStack.h"
//创建单个结点
ST* StackBuy(SDataType x) {
ST* newnode = (ST*)malloc(sizeof(ST));
if (newnode == NULL) {
printf("malloc fail");
exit(-1);
}
newnode->data = x;
newnode->next = NULL;
return newnode;
}
//SLStack.c
//入栈
void StackPush(ST** top, SDataType x) {
assert(top);//如果传的是指针变量的值 报错
ST* newnode = StackBuy(x);
if (*top == NULL) { //为空直接指向新结点
*top = newnode;
}
else {
newnode->next = *top; //链表头插
*top = newnode;
}
}
//SLStack.c
//出栈
void StackPop(ST** top) {
assert(!StackEmpty(top));
if ((*top)->next == NULL) {
free(*top);
*top = NULL;
}
else {
ST* prev = (*top)->next; //链表头删
free(*top);
*top =prev;
}
}
//SLStack.c
//判空
bool StackEmpty(ST** top) {
return (*top)==NULL;
}
//SLStack.c
//销毁栈
void StackDestroy(ST** top) {
ST* cur = *top;
while (cur) {
ST* next = cur->next;
free(cur);
cur = next;
}
}
//SLStack.c
//查看栈顶值
SDataType StackTop(ST** top) {
assert(!StackEmpty(top));
return (*top)->data;
}
//SLStack.c
//查看有效数据量
int StackSize(ST** top) {
assert(!StackEmpty(top));
int i = 1;
ST* cur = *top;
while (cur->next) {
cur = cur->next;
i++;
}
return i;
}
思路:
C语言代码实现
//... //由于C没有栈,在这之前先得把C中实现的栈搬过来。 //头文件和源文件 //... bool isValid(char * s){ ST st; StackInit(&st); while(*s) { //左括号全部入栈 if(*s == '{' || *s=='[' || *s=='(') { StackPush(&st, *s); } //遇到右括号出栈匹对 else { //针对空与右括号多的情况 if(StackEmpty(&st)) { return false; } STDataType top = StackTop(&st); if((*s == '}' && top != '{') || (*s == ']' && top != '[') || (*s == ')' && top != '(')) { return false; } StackPop(&st); } s++; } //针对左括号多的情况 bool flag = StackEmpty(&st); return flag; }
栈的实现总体来说,用数组实现是非常容易的,链式栈的实现相对有点复杂,链式栈如果用尾插尾删的方式实现入栈进栈,需要每次遍历尾部结点,所以通过头插头删实现会更加便利。
以下是完整代码:
完整代码
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。