堆栈(Stack)
堆栈是具有一定操作约束的线性表,典型特征是 先入后出(Last In First Out)。
即只在一端做插入(push)和删除(pop),这两种基本操作又叫做入栈和出栈。
栈的顺序储存结构: 有一个一维数组和一个记录栈顶元素位置的变量组成。
#define MAXSIZE 10
typedef struct SNode *Stack;
template <typename E>
struct SNode{
E data[MAXSIZE];
int top;
};
Stack Create()
{
Stack s = (Stack)malloc(sizeof(struct SNode));
s->top = -1;
return s;
}
bool IsFull(Stack s)
{
if(s->top+1 == MAXSIZE)
{
cout<<"栈已满"<<endl;
return true;
}
else return false;
}
bool IsEmpty(Stack s)
{
if(s->top+1 == 0)
{
cout<<"栈是空的"<<endl;
return true;
}
else return false;
}
bool Push(Stack s,E x)
{
if(IsFull) return false;
else
{
s->top++;
s->data[top] = x;
return true;
}
}
#define ERROR <E类型的特殊值,标志错误>
E Pop(Stack s)
{
if(IsEmpty) return ERROR;
else
{
E x = s->data[top];
s->top--;
return x;
}
}
栈的链式储存结构: 实际上就是一个单链表,叫做链栈。但是链栈的插入和删除操作只能在链栈的栈顶进行。
~
链栈中栈顶标志 top 应该在链表的哪一头呢?
如果在链表的尾结点处,试想入栈操作和出栈操作的实现。
入栈简单,只需要将新结点 s 接在尾结点后面即可,即 s->next = top->next, top = s。
出栈操作呢?链栈的出栈需要找到top的前一个结点,将其作为新的 top ,但这是单向链表,只知道尾结点,是找不到其他结点的,因为它只能根据 next 向后遍历。
所以 top 应该在链表的头结点。
~
实现: 初始化一个空的头结点,无论是出栈还是入栈,对象都是这个头结点的下一个结点(入栈时,头结点的下一个节结点就是新结点)。
typedef struct SNode *Stack;
template <typename E>
struct SNode{
E data;
Stack next;
};
Stack create()
{
Stack s = (Stack)malloc(sizeof(struct SNode));
s->next = NULL;
return s;
}
bool IsEmpty(Stack s)
{
if(s->next == NULL)
{
cout<<"栈是空的"<<endl;
return true;
}
else return false;
}
void Push(Stack s,E x)
{
Stack p = (Stack)malloc(sizeof(struct SNode));
p->data = x;
p->next = s->next;
s->next = p;
}
#define ERROR <E类型的特殊值,表示栈空,出栈失败>
E Pop(Stack s)
{
if(IsEmpty) return ERROR;
else
{
Stack p = s->next;
s->next = p->next;
E x = p->data;
free(p);
return x;
}
}