今天敲得是栈。栈是一种特殊的存储方式,这种方式就像往箱子里面放东西,先放进去的后拿出来,后放进去的先拿出来。老师是用数组的形式实现,我用链表的形式实现。来看代码吧。
老师版
创建
#include <stdio.h>
#include <malloc.h>
#define STACK_MAX_SIZE 10
typedef struct CharStack{
int top;
int data[STACK_MAX_SIZE];
}*CharStackPtr;
CharStackPtr CharStackInit()
{
CharStackPtr resultPtr = (CharStackPtr)malloc(sizeof(CharStack));
resultPtr->top=-1;
return resultPtr;
}
我们在结构体里设置了一个名为top的变量,它的作用就是始终指向最顶部,也就是最后放进去的元素。
压栈
这副动态图很形象的解释了压榨,每放入一个元素,都使top往后移一位,使之始终指向栈顶的元素。
void push(CharStackPtr paraStackPtr,int paraValue)
{
if((paraStackPtr->top)>=STACK_MAX_SIZE -1)
{
printf("Can not push element:stack is full.");
return;
}
paraStackPtr->top ++;
paraStackPtr->data[paraStackPtr->top] = paraValue;
}
出栈
出栈操作也十分简单,元素移出,让top前移。
char pop(CharStackPtr paraStackPtr)
{
if(paraStackPtr->top<0)
{
printf("Can not pop element:stack empty.\r\n");
return '\0';
}
paraStackPtr->top --;
return paraStackPtr->data[paraStackPtr->data +1];
}
测试代码
void pushPopTest() {
char ch;
int i;
printf("---- pushPopTest begins. ----\r\n");
CharStackPtr tempStack = CharStackInit();
printf("After initialization, the stack is: ");
outputStack(tempStack);
for ( ch = 'a'; ch < 'm'; ch ++) {
printf("Pushing %c.\r\n", ch);
push(tempStack, ch);
outputStack(tempStack);
}
for ( i = 0; i < 3; i ++) {
ch = pop(tempStack);
printf("Pop %c.\r\n", ch);
outputStack(tempStack);
}
printf("---- pushPopTest ends. ----\r\n");
}
int main() {
pushPopTest();
}
运行结果
---- pushPopTest begins. ----
After initialization, the stack is:
Pushing a.
a
Pushing b.
a b
Pushing c.
a b c
Pushing d.
a b c d
Pushing e.
a b c d e
Pushing f.
a b c d e f
Pushing g.
a b c d e f g
Pushing h.
a b c d e f g h
Pushing i.
a b c d e f g h i
Pushing j.
a b c d e f g h i j
Pushing k.
Can not push element:stack is full.a b c d e f g h i j
Pushing l.
Can not push element:stack is full.a b c d e f g h i j
Pop j.
a b c d e f g h i
Pop i.
a b c d e f g h
Pop h.
a b c d e f g
---- pushPopTest ends. ----
自己版
我自己写了链式栈的基本算法的代码,附在下方
创建
链式栈需要两个结构体,一个定义节点,另外一个定义栈顶和栈底。
typedef struct Node
{
int data;
struct Node *next;
}NODE,*PNODE;
typedef struct Stack
{
PNODE pTop;
PNODE pBottom;
}STACK,*PSTACK;
void initStack(PSTACK pS)
{
printf("init\r\n");
pS->pTop = (PNODE)malloc(sizeof(NODE));
pS->pBottom = pS->pTop ;
pS->pTop ->next=NULL;
return;
}
在写创建这代码的时候,我遇到了一个令我百思不得其解的问题。因为创建其实理解起来很简单,让栈顶和栈底相等,然后栈顶指向为空即可。
一开始,我让栈顶和栈底相等是这样写的:
pS->pTop = pS->pBottom ;
但是却怎么也无法压栈和出栈,我甚至为此把所有代码重新敲了一遍。后来,再一次对我的代码的修改时我将这两者互换了位置,突然就全部都运行了。
然后我看了这一小段代码的网课,原来在我已经给pTop动态分配了内存,但是pBottom却仍然是一堆垃圾值,而我们应该给pBottom赋值并且使他们指向同一处。而把pTop赋值给pBottom才能使他们指向同一处。
压栈
void pushStack(PSTACK pS,int val)
{
printf("push\r\n");
PNODE p;
p=(PNODE)malloc(sizeof(NODE));
p->data =val;
p->next =pS->pTop ;
pS->pTop =p;
}
出栈
void popStack(PSTACK pS)
{
printf("pop\r\n");
PNODE p;
p=(PNODE)malloc(sizeof(NODE));
p=pS->pTop ;
pS->pTop =p->next ;
free(p);
p=NULL;
}
运行结果
init
11
push
push
push
push
22
print
4 3 2 1 33
pop
print
3 2 1
总结
实际上栈的算法很好理解,无非是先进后出,后进先出八字。
但是栈虽然简单,却能解决生活中很多问题,比如下面的括号匹配问题。
栈的应用–括号匹配
由于栈的实现和之前的完全一样,所以这里我只列出最主要的括号匹配部分的代码。
bool bracketMatching(char* String, int Length)
{
CharStackPtr stack = initStack();
int i;
char tempch,popch;
pushStack(stack,'#');
for(i=0;i<Length;i++)
{
tempch=String[i];
switch(tempch)
{
case '(':
case '[':
case '{':
pushStack(stack,tempch);
break;
case')':
popch=popStack(stack);
if(popch!='(')
{
return false;
}
break;
case']':
popch=popStack(stack);
if(popch!='[')
{
return false;
}
break;
case'}':
popch=popStack(stack);
if(popch!='}')
{
return false;
}
break;
default:
break;
}
}
popch=popStack(stack);
if(popch!='#')
{
return false;
}
return true;
}
这一段代码的逻辑思想也很简单,理解之后敲起来就十分顺手。当我们在表达式中遇到了‘(,【,}’这几个括号时,我们进行压栈操作,将这几个括号存入栈中,接着,如果我们遇到了‘),】,}’这几个括号中的一个时,我们进行出栈操作,如果此时弹出的元素和此时遇到的括号对应,就接着循环找到下一个括号,否则就返回‘0’,也就是不匹配。
在代码中,我们还设置了“#”标识符,当我们匹配结束却仍然没有弹出“#”,证明我们多了一个括号没有匹配到,也会返回“0”。
另外,代码中的变量和老师的略有差异,因为我是自己敲得,所以改变了部分变量名。
运行结果
Is the expression '[2 + (1 - 3)] * 4' bracket matching? 1
Is the expression '( ) )' bracket matching? 0
Is the expression '()()(())' bracket matching? 1
Is the expression '({}[])' bracket matching? 0
Is the expression ')(' bracket matching? 0