文档库 最新最全的文档下载
当前位置:文档库 › 数据结构之数据栈C源代码

数据结构之数据栈C源代码

数据结构之数据栈C源代码
数据结构之数据栈C源代码

玩转算法与数据结构之数据栈

—HIT2000鲁天伟

前面我们讲了单链表,双向链表,循环链表。这几种链表形式向我们展示了一种数据线性存储方式。现实世界中,人们利用建筑材料建造房子用来住人,住人房子有大有小,在计算机世界人们利用计算机语言也是建房子给数据住。每个房子都有地址,但是房子中住的人是可以变的。计算机一样,定义变量,计算机根据变量数据类型的大小分配一块连续内存,用来存放相应类型的数据。并把这块内存的首地址作为这个数据变量的寻址地址。链表这种存储方式只要知道表头结点的地址,就能按顺序知道其它结点的地址和地址中存储的数据。如果一直增加结点可以一直连下去,直到把计算机中能用的内存地址用完。如果数据链太长,是否对我们是有用的,是否好管理,好操作呢?如果这条链无限长,相当于把整个内存作为一个容器来存放这些数据。也就是可以用无限制长度的链表作无限数据存储,结点可以一直增加。这个是数组这种数据类型不具备的功能,数组初始化后就定长了,到达指定长度,无法继续拓展。而且数组插入,删除数据还要调整后面数据在数组中的位置,这点上无限制长度链表要比数组灵活方便的多。数据链太长了是否不太好管理呢,因此我们要根据需要,使用不同大小形状的容器来灵活的管理。其中一种是数据栈,用来存放管理数据。类似货栈,用来存货的,粮栈用来存粮的。但是无论货栈还是粮栈都是有大小限制的。我们定义的数据栈也限制它的大小,一个数据栈装满了数据,没装完可以再建一个新的数据栈来装数据。装数据的时候,模拟粮仓装粮食一样,最先装进去的粮食在最下面,在取用时最后装进去的粮食,由于在上面所以会先取到。也就是让数据先进后出,类似给弹夹装子弹,一颗一颗压下去。压到最上面一颗满了,就不能装了。打子弹的时候从先用弹夹最上面的子弹,弹夹子弹打空了,也就不能再打出子弹了。也就是在进行装填数据时还要一直记录数据的个数,看是否为空,是否超过最大值。

如此,我们给出栈的定义:

栈有高度,宽度,数据进出的顺序是先进后出,栈满不可再增加数据,栈空不可再弹出数据。每次录入一条记录,每次弹出只有一条记录。

具体解释:栈是一个有限大小的数据容器,高度的定义是可输入数据记录的条数。宽度的定义是每层一条记录。这一条记录可以包含1个或多个数据元素,如下三种情况,每个花括号内是一条记录:

a)比如{1},{2},{3} ,每条记录只有一个种数据类型,例子中是整型。

b)比如{1,2,3},{4,5,6},{7,8,9},每条记录含有3个同种数据类型的数据,例子中是整型。

c)比如{1,‘a’,”blue”},{2,’b’,’yellow’},{3,’c’,”red”} 每条记录含有不同的数据类型的三个元素,例

子中,每条记录包含1个整型数据,1个字符型数据,1个字符串型数据。

先进后出的录入顺序:可以把数据记录按顺序一条一条的录入,录数据时候从前向后录入(一层一层录入),取数据的时候从后向前按顺序一条一条的取。其它教材上都是把栈讲成是立着的数组图,我这边把栈放平,左边是栈底,右边是栈顶,这样让大家更好理解,和我们计算机输入和书写习惯保持一致。栈底数据是录入的第一条记录,然后从左向右录入,栈顶数据是当前存储的最右边的数据。取出栈顶数据,也就是从数据栈最右边取出记录。被取出记录的原相邻的左侧记录成为新的栈顶数据。

栈满:当栈录入的记录条数超过最大值时,判定栈容量已满,不能再增加数据。

栈空:当栈中已经没有数据记录时,判定栈已空,不能再取出数据。

如下图:

将a,b,c,d四个数据放入(入栈),大小为4的栈中,从左向右逐个放入。到第四个栈满。不能再放入,取数据(出栈)的时候,图从右向左看。也就是要在每次放入或取出数据时,要记录栈顶的位置,数据入栈前要判断是否栈满,栈满不能入栈。出栈前判断栈是否为空,空则不能输出数据。

对于一个有限长度的数据集合,我们如何实现它的存储呢。可以用数组,也可以用链表。

a)如果用数组有如下几种情况:

1、如果每条记录中只有一个种类型的数据,且只有一个数据,我们可以采用简单的数

组来存放。比如{2},{3},{4}, 可以用int stack[Maxsize], Maxsize是栈的最大记录条数。

2、如果每条记录中有多个数据,且数据类型相同,比如整型{1,2,3}这是一条记录,我

们可以用三维数数组来作,比如int stack[3][Maxsize] , 或是int stack[Maxsize][3]来

作为存储容器。

3、如果每条记录中有多个数据,且数据类型不相同,比如{1,‘a’,2.5}这是一条记录我们

可以用结构体数组来作为存储容器。例如:

Struct record{ /*定义记录的结构体*/

Int a;

Char b;

Float c

};

Struct record stack[Maxsize];

用这种结构体数组来存储记录数据。

4、针对第3种情况每条记录中含有多个数据,也可以用三个基础数据类型数组来实存

储。例如:

Int stack1[Maxsize];

Char stack2[Maxsize];

Float stack3[Maxsize];

以上是用数组作为存储容器的4种情况,采用不同的存储方式,配合不同的入栈和出栈方法(存储容器不一样,当然要配合不同的装填和取用的方法),但方法都要遵循先进后出的原则。入栈前栈不能满,出栈时栈不能空的原则。

因此可以定义方法如下:/*以最简单的一维数组为例。*/

#define MaxSize 25 /*定义栈的容量最大录入记录数*/

Int Data[MaxSize]; /*栈数组*/

Int top; /*栈顶标志*/

Int push(int * Data,int indata,int *topaddr); /*在栈中压入数据*/

Int pop(int * Data,int * outdata,int * topaddr); /*在栈中弹出数据*/

Int isEmpty(int top); /*判断栈是否为空*/

Int isFull(int top); /*判断栈是否为满*/

因为栈数组和栈顶标志是配合使用的,是一对一的关系,也可以封装到一起,如下面的写法:

#define MaxSize 25 /*定义栈的容量最大录入记录数*/

struct stack{ /*把静态变量封装在栈的结构体里*/

Int data[MaxSize]; /*栈数组*/

Int top; /*栈顶标志*/

};

typedef struct stack StackArray;

typedef StackArray * Stack;

int push(Stack stackaddress,int indata); /*在栈中压入数据*/

int pop(Stack stackaddress,int * outdataaddr); /*从栈中弹出数据*/

Int isEmpty(Stack stackaddress); /*判断栈是否为空*/

Int isFull(Stack stackaddress); /*判断栈是否为满*/

b)如果用链表来作存储介质。

#define MaxSize 25 /*定义栈的容量最大录入记录数*/

struct list{ /*定义链表结点*/

int data; /*定义结点数据变量*/

int * next; /*定义指向下个结点的指针变量*/

};

Typedef struct list listNode;

Typedef listNode * stack;

stack push(stack Stack,int indata,int * topaddr);

stack pop(stack Stack,int * outdata,int * topaddr);

int isEmpty(int top);

int isFull(int top);

链表的结点个数根据入栈和出栈的操作在0到MaxSize值之间动态的增加,减少。数组是一次按最大值把内存申请出来。

以上所有方法中的判断栈满isFull和判断栈空isEmpty的方法根据编码习慢,可以选择实现也可以不实现。因为判断的语句比较简单,也可以在push和pop方法中直接判断栈的空满情况。写出来就是让大家关注到栈的容量问题。

下面分别用数组和链表来实现数据栈。

1)如下是可执行的栈的数组实现源代码。

/*====================begin===========================*/

#include

#define MaxSize 8

/*======将数据压入数组栈中======*/

void push(int* stack,int data,int* topaddr){

if(*topaddr

* topaddr=*topaddr+1;

stack[*topaddr]=data;

}

else

printf("The stack is full\n");

}

/*======从数组栈中取数据======*/

void pop(int* stack,int* temp,int*topaddr){

if(*topaddr==-1)

printf("the stack is empty\n");

else{

* temp = stack[*topaddr];

*topaddr=*topaddr-1;

}

}

/*======打印数组栈中数据=====*/

void printstack(int* stack,int top){

int i;

if(top==-1){

printf("The stack is empty\n");

}

else{

for(i=0;i<=top;i++){

printf("%d ",stack[i]);

}

printf("\n");

}

}

void main(){

int a;

int b;

int c;

int top=-1;/*数组栈的栈顶标识*/

int stack[MaxSize];/*数组0号位置为栈底,栈可录入MaxSize条记录*/

do{

printf("please input your choice\n1.push\n2.pop\n3.print\n4.quit\n"); scanf("%d",&a);

switch(a){

case1:printstack(stack,top);

printf("input the data you want to push\n");

scanf("%d",&b);

push(stack,b,&top);

printstack(stack,top);

break;

case2:printstack(stack,top);

pop(stack,&c,&top);

printf("The pop data is %d\n",c);

printstack(stack,top);

break;

case3:printstack(stack,top);

break;

case4:break;

default:printf("please input choice from 1 to 4\n");break;

}

}while(a!=4);

getch();

}

/*=====================end============================*/ 2)栈的链表实现如下:

/*====================begin===========================*/ #include

#include

#define MaxSize 8

struct list{/*定义链表结点*/

int data;/*定义结点数据变量*/

struct list * next;/*定义结点指向下个结点的指针变量*/

};

typedef struct list Node;/*链表结点别名*/

typedef Node * link;/*链表结点指针别名*/

/*======将数据压入数组栈中======*/

link push(link stack,int data,int* topaddr){

link newNode;

if(* topaddr==MaxSize){

printf("Stack if full\n");

}

else{

newNode=(link)malloc(sizeof(Node));

newNode->data=data;

newNode->next=NULL;

if(stack==NULL){

stack=newNode;

}

else{

newNode->next=stack;

stack=newNode;

}

*topaddr=*topaddr+1;

}

return stack;

}

/*======从数组栈中取数据======*/

link pop(link stack,int* temp,int* topaddr){

link pointer;

if(stack==NULL){

printf("Stack is empty\n");

}

else{

* temp=stack->data;

pointer=stack;

stack=stack->next;

free(pointer);

*topaddr=*topaddr-1;

}

return stack;

}

/*======打印数组栈中数据=====*/

void printList(link stack){

link pointer;

if(stack==NULL)

printf("The stack is empty\n");

else{

pointer=stack;

while(pointer!=NULL){

printf("%d ",pointer->data);

pointer=pointer->next;

}

printf("\n");

}

}

/*======递归反转打印数组栈=====*/

void printcoverse(link stack){

if(stack!=NULL){

printcoverse(stack->next);

printf("%d ",stack->data);

}

}

void main(){

int a,b,c;

link stack=NULL;/*初始化栈顶指针为0,当前是空栈*/

int top=0;/*结点计数器初始化*/

do{

printf("choice:\n1.push\n2.pop\n3.printnomal\n4.printconvers\n5.quit\ n");

scanf("%d",&a);

switch(a){

case1:

printList(stack);

printf("input data you want to push\n");

scanf("%d",&b);

stack=push(stack,b,&top);

printList(stack);

break;

case2:printList(stack);

stack=pop(stack,&c,&top);

printList(stack);

break;

case3:printList(stack);break;

case4:printcoverse(stack);printf("\n");break;

case5:break;

default:printf("Please input your choice from 1 to 5\n");

break;

}

}while(a!=5);

getch();

}

/*=====================end============================*/

我自己使用的环境是运用notepad++编辑,在notepad++里调用Dev-CPP里的编译和运行。具体网上有教程很简单,两个软件安装完成后,简单在计算机里配一下环境变量即可。使用graphviz软件进行数据结构图形的绘画,这个软件非常好,推荐大家使用。

当然程序在VC6.0,Tubo C,还有Win-TC中也都能正常运行。用C语言的编译运行工具都可以用上面的源代码。

源代码文件如下:

stackArray.c stackList.c

2020-9-15

HIT2000 软件学院鲁天伟

相关文档