您的位置:首页 > 编程语言 > C语言/C++

C语言实现栈(基于链表)

2016-11-26 23:00 288 查看
栈的底层数据结构可以是数组,也可以是链表,用链表实现栈,理论上是无限大的

下面是链栈的实现代码

#include<stdbool.h>
#include<stdlib.h>
typedef int datatype;

//Link Stack 实现顺序栈,使用链表来实现

// struct LinkList
// {
// datatype data;
// struct LinkList *next;
// };

struct stack
{
datatype data;
struct stack *next;
};

typedef struct stack Stack;
//创建栈
Stack *s;
//初始化栈
void init()
{
s=NULL;
}

//判断栈是否为空
bool Empty()
{
if(s==NULL)
{
return true;
}
else
{
return false;
}
}

//判断栈是否已满了
// void full(Stack *s)
// {
// if(s->top==realsize-1)
// {
// realsize++;
// s->data=(datatype *)realloc(s->data,realsize);
// }
// }

//入栈
void Push(datatype element)
{
Stack *p = (Stack *)malloc(sizeof(Stack));
p->data=element;
p->next=s;
s=p;
}

//出栈
void Pop()
{
if(!Empty(s))
{
s=s->next;
}
else
{
printf("栈空\n");
}
}

//取栈顶元素
datatype Top()
{
if(!Empty(s))
{
return s->data;
}
else
{
printf("栈空\n");
}
}

//销毁栈
void Destroy()
{
free(s);//因该销毁每一个元素
s=NULL;
// free(s.data); //容易导致失败
}
测试代码

#include<stdio.h>
#include "LinkStack.h"
int main()
{
int i=0;
// struct stack s;
//初始化栈
printf("\n###########初始化栈###########\n");
init();
printf("----------------------------------");
//入栈操作
printf("\n###########入栈操作###########\n");
for(i=0;i<=10;i++)
{
Push(i);
}
printf("----------------------------------");
printf("\n###########取栈顶元素###########\n");
printf("%d\n",Top());
printf("----------------------------------");
//出栈操作
printf("\n###########出栈操作###########\n");
for(i=0;i<=12;i++)
{
Pop();
}
printf("----------------------------------");
printf("\n###########取栈顶元素###########\n");
Top();
printf("----------------------------------");
printf("\n###########销毁栈############\n");
Push(10);
Destroy();
Top();
}

这样的栈和之前数组实现的栈有共同的缺点,无法自己定义多个栈,但是全局变量避免了一个容易出错的地方,下面会说到

这里要实现和前一篇数组实现栈的自己定义多个栈,如果套用之前的方法,就会出现一个错误,数组是直接把栈作为参数传入函数,对栈的修改,就会改变原来栈的元素值。

但是这里链栈,把指针作为参数传入函数,修改参数指针指向,并不会,改变原来的指针

有两种方法可以实现,一种是将指针作为函数值返回,另一种是使用二级指针

先看第一种方法的栈的实现

#include<stdbool.h>
#include<stdlib.h>
// #define maxsize 10
typedef int datatype;

//Link Stack 实现顺序栈,使用链表来实现

// struct LinkList
// {
// datatype data;
// struct LinkList *next;
// };

struct stack
{
datatype data;
struct stack *next;
};

typedef struct stack Stack;

// Stack *s;
//初始化栈
Stack* init(Stack *s)
{
s=NULL;
return s;
}

//判断栈是否为空
bool Empty(Stack *s)
{
if(s==NULL)
{
return true;
}
else
{
return false;
}
}

//判断栈是否已满了
// void full(Stack *s)
// {
// if(s->top==realsize-1)
// {
// realsize++;
// s->data=(datatype *)realloc(s->data,realsize);
// }
// }

//入栈
Stack* Push(Stack *s,datatype element)
{
Stack *p = (Stack *)malloc(sizeof(Stack));
p->data=element;
p->next=s;
s=p; //这里指针只是副本,无法修改原来的指针,要么使用二级指针,要么返回这个指针
return s;
}

//出栈
Stack* Pop(Stack *s)
{
if(!Empty(s))
{
s=s->next;
}
else
{
printf("栈空\n");
}
return s;
}

//取栈顶元素
datatype Top(Stack *s)
{
if(!Empty(s))
{
return s->data;
}
else
{
printf("栈空\n");
}
}

//销毁栈
Stack* Destroy(Stack *s)
{
free(s);//因该销毁每一个元素
s=NULL;
return s;
// free(s.data); //容易导致失败
}

栈的测试代码

#include<stdio.h>
#include "LinkStack1.0.h"
int main()
{
int i=0;
Stack p;
Stack *s;
s=&p;
// struct stack s;
//初始化栈
printf("\n###########初始化栈###########\n");
s=init(s);
printf("----------------------------------");
//入栈操作
printf("\n###########入栈操作###########\n");
for(i=0;i<=10;i++)
{
s=Push(s,i);
}
printf("----------------------------------");
//取栈顶元素
printf("\n###########取栈顶元素###########\n");
printf("%d\n",Top(s));
printf("----------------------------------");
//出栈操作
printf("\n###########出栈操作###########\n");
for(i=0;i<=12;i++)
{
s=Pop(s);
}
printf("----------------------------------");
//取栈顶元素
printf("\n###########取栈顶元素###########\n");
Top(s);
printf("----------------------------------");
//销毁栈
printf("\n###########销毁栈###########\n");
s=Push(s,10);
s=Destroy(s);
Top(s);
}

这种办法比较麻烦,增加了使用者的负担,增加了代码量

再看第二种方法,二级指针(指针的指针)栈的实现

#include<stdbool.h>
#include<stdlib.h>
// #define maxsize 10
typedef int datatype;

//Link Stack 实现顺序栈,使用链表来实现

struct LinkList
{
datatype data;
struct LinkList *next;
};

typedef struct stack* Stack;

//初始化栈
void init(Stack *s)
{
*s=NULL;

}

//判断栈是否为空
bool Empty(Stack *s)
{
if(*s==NULL)
{
return true;
}
else
{
return false;
}
}

//判断栈是否已满了
// void full(Stack *s)
// {
// if(s->top==realsize-1)
// {
// realsize++;
// s->data=(datatype *)realloc(s->data,realsize);
// }
// }

//入栈
void Push(Stack *s,datatype element)
{
Stack *p = (Stack *)malloc(sizeof(struct LinkList));
p->data=element;
p->next=*s;
*s=p; //这里指针只是副本,无法修改原来的指针,要么使用二级指针,要么返回这个指针
}

//出栈
void Pop(Stack *s)
{
if(!Empty(s))
{
*s=(*s)->next;
}
else
{
printf("栈空\n");
}
}

//取栈顶元素
datatype Top(Stack *s)
{
if(!Empty(s))
{
return (*s)->data;
}
else
{
printf("栈空\n");
}
}

//销毁栈
void Destroy(Stack *s)
{
free(s);//因该销毁每一个元素
*s=NULL;
// free(s.data); //容易导致失败
}
栈的测试代码

#include<stdio.h>
#include "LinkStack2.0.h"
int main()
{
int i=0;
Stack p;
Stack *s;
s=&p;
// struct stack s;
//初始化栈
printf("\n###########初始化栈###########\n");
init(s);
printf("----------------------------------");
//入栈操作
printf("\n###########入栈操作###########\n");
for(i=0;i<=10;i++)
{
Push(s,i);
}
printf("----------------------------------");
//取栈顶元素
printf("\n###########取栈顶元素###########\n");
printf("%d\n",Top(s));
printf("----------------------------------");
//出栈操作
printf("\n###########出栈操作###########\n");
for(i=0;i<=12;i++)
{
Pop(s);
}
printf("----------------------------------");
//取栈顶元素
printf("\n###########取栈顶元素###########\n");
Top(s);
printf("----------------------------------");
//销毁栈
printf("\n###########销毁栈###########\n");
Push(s,10);
Destroy(s);
Top(s);
}

这样即可实现链栈。这里指针作为参数传递进函数,实际上只是一份拷贝,只是这分拷贝和原来的指针是同一个指向,所以改变指针指向的内容,是可以的,但是改变指针本身是错误的,所以需要二级指针
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息