前言
参考书籍 :《大话数据结构》
编程语言:C语言。
涉及的头文件,后面代码省略了,请自行补上。
#include<stdio.h>
#include<assert.h>
栈的定义(回顾)
栈的定义:栈是一种特殊的线性表。栈限定仅在表尾进行插入和删除操作。
其中允许在一端进行数据的插入与删除的操作,被称为栈顶,而另一端则被称为栈底。
专业名词:
出栈:删除尾端的元素。
入栈/压栈/进栈:往尾端插入元素。
空栈:没有存储任何元素。
顺序结构(定长数组)实现栈—静态栈
由于大话数据结构这本书采取的是定长数组实现栈,所以先说明这种。
实现栈的函数。
//栈的初始化
//压栈操作
//出栈操作
//栈的销毁
大体写那些函数就行了,后面遇到要额外写的函数后面再补上就是。
栈的长度:栈的有效数据的元素个数。
设计思路:定长数组的下标为0处为栈底,数组最大下标实际有效长度减一作为栈顶,那么top指向的就是栈顶的有效元素,top+1是下一位插入元素的位置
#define MAX_COUNT 100
typedef int StackDataType;//StackDataType根据实际情况而定,这里假设为int。
typedef struct stack {
int top;//栈顶指针
StackDataType data[MAX_COUNT];//定长数组
}ST;
栈的初始化
void STInit(ST* ps) {
assert(ps);
ps->top = -1;
int i = 0;
for (i = 0; i < MAX_COUNT; i++) {
ps->data[i] = 0;
}
}
栈的销毁
void STDestory(ST* ps) {
STInit(ps);//局部变量出作用域自动销毁,不用特地销毁。
}
压栈
void STPush(ST* ps,StackDataType x) {
assert(ps);
//判断栈满了没
assert(ps->top != MAX_COUNT);
ps->data[++ps->top] = x;
}
出栈
void STPop(ST* ps) {
assert(ps);
//判断是否为空栈
assert(ps->top != -1);
--ps->top;
}
栈打印
void STPrint(ST* ps) {
assert(ps);
int i = 0;
for (i = 0; i <50; i++)
printf("-");
printf("\n|");
for (i = 0; i <= ps->top; i++)
{
printf("%d->", ps->data[i]);
}
printf("null\n");
for (i = 0; i < 50; i++)
printf("-");
printf("\n");
}
简单评价一下静态栈
压栈出栈时间复杂度O(1),快。连续的物理空间存储数据。
缺点浪费空间,不灵活。实际中并不适用。
链式结构实现栈—链栈
链式结构肯定用链表呗,用哪种链表呢?
显然单链表,单向不循环链表。带哨兵位方便,带头结点。
单链表的头部很适合作为栈顶。为什么不选择尾部?因为单链表的毒点就是进行尾插尾删要遍历整个链表找尾。选头部最适合。
压栈:即(带哨兵位)单链表的头插。
出栈:即(带哨兵位)单链表头删。
链栈的定义
typedef int StackDataType;
typedef struct stack {
StackDataType data;
struct stack* next;
}ST;
ST* top = NULL;//栈顶指针
ST* base = NULL;//栈底指针,也就是头指针指向哨兵位。
#include<assert.h>
#include<stdio.h>
#include<stdlib.h>
typedef int StackDataType;
typedef struct stack {
StackDataType data;
struct stack* next;
}ST;
ST* STBuyNode(StackDataType x);
ST* STInit(void) {
ST* tmp = (ST*)malloc(sizeof(ST));
if (tmp == NULL) {
perror("malloc fail");
exit(-1);
}
tmp->data = -1;
tmp->next = NULL;
return tmp;
}
void STPush(ST** pphead,StackDataType x) {
assert(pphead);
assert(*pphead);
ST* newnode = STBuyNode(x);
newnode->next = *pphead;
*pphead = newnode;
}
void STPrint(ST* phead) {
if (phead==NULL) {
printf("NULL");
return;
}
ST* pcur = phead;
while (pcur->next)
{
printf("%d->", pcur->data);
pcur = pcur->next;
}
printf("哨兵位->NULL\n");
}
void STPop(ST** pphead) {
assert(pphead);
assert(*pphead);
assert((*pphead)->next);//判断此处是不是哨兵位,如果是则不能在头删了。
//改变栈顶指针的指向。
ST* tmp = *pphead;
*pphead = (*pphead)->next;
free(tmp);
}
ST* STBuyNode(StackDataType x) {
ST* newnode = (ST*)malloc(sizeof(ST));
if (newnode == NULL) {
perror("malloc fail!");
exit(-1);
}
newnode->data = x;
newnode->next = NULL;
return newnode;
}
void STDestory(ST** top,ST** base) {
assert(top && base);
assert(*top && *base);
ST* pcur = *top;
ST* next = *top;
while (pcur) {
next = pcur->next;
free(pcur);
pcur = next;
}
*top = NULL;
*base = NULL;
}
int main() {
ST* top = NULL;//栈顶指针
ST* base = NULL;//栈底指针,也就是头指针指向哨兵位。
top = base = STInit();
STPush(&top, 1);
STPush(&top, 1);
STPush(&top, 1);
STPrint(top);
STPop(&top);
STPrint(top);
STDestory(&top, &base);
STPrint(top);
return 0;
}