1.顺序栈的存储结构定义
#define STACKINCREMENT 10
#define STACK_INIT_SIZE 100
typedef int SElemType
typedef struct {
SElemType* base;
SElemType* top;
int stacksize;
}SqStack;
2.顺序栈基本操作的实现—初始化/销毁/置空等
Status InitStack(SqStack& S) {
S.base = (SElemType*)malloc(STACK_INIT_SIZE * sizeof(SElemType));
if (!S.base)
exit OVERFLOW;
S.top = S.base;
S.stacksize = STACK_INIT_SIZE;
return OK;
}
思路:操作和线性表很像。首先栈底开辟空间,判断存储是否分配失败。进行空栈赋值处理。然后赋值栈空间大小。最后返回。
总结下来就是开辟空间,判断是否开辟成功,空栈处理,栈空间赋值处理。三步操作。
Status DestroyStack(SqStack& S) {
free(S.base);
S.base = NULL;
S.top = NULL;
S.stacksize = 0;
return OK;
}
销毁空间,指针赋空,空间大小赋空。结束。
Status ClearStack(SqStack &S){
S.top=S.base;
return OK;
}
base指针永远指向栈底,top指针不停向上移动。当两指针指向相同时即为空栈。
Status StackEmpty(SqStack S)
{
if (S.top == S.base)
return TRUE;
else return FALSE;
}
int StackLength(SqStack S)
{
return (S.top - S.base);
}
Status GetTop(SqStack S, SElemType& e) {
if (S.top == S.base)
return ERROR;
e = *(S.top - 1); //注意top指向待插入位置
return OK;
}
Status StackTraverse(SqStack S, Status(*visit)(ElemType)) {
//从栈底元素到栈顶元素依次执行visit函数,常用于输出栈中元素
ElemType* p = S.base;
while (p < S.top) {
if (visit(*p) == ERROR)
return ERROR;
++p;
}
return OK;
}//除遍历操作外时间复杂度均O(1)
3.入栈与出栈
Status Push(SqStack& S, SElemType e) {
if (S.top - S.base == stacksize) {
S.base = (SElemType*)realloc(S.base, (S.stacksize + STACKINCREMENT) * sizeof(SElemType);
if (!S.base)
exit OVERFLOW;
S.top = (S.base + S.stacksize);//使得S.top重新指向栈顶,因realloc
S.stacksize += STACKINCREMENT;
}
*S.base=e;
S.base++;
return OK;
}
入栈Push:判断栈满,若满需要扩容,判断空间分配是否成功,栈顶位置改变,栈容量改变。
插入元素赋值,指针上移。
Status Pop(SqStack& S, SElemType& e) {
if (S.top == S.base)
return ERROR;
e = *S.top;
*S.top--;
return OK;
}
出栈Pop:判断是否栈空,传回元素值,指针下移。
4.链栈的定义与实现
4.1存储结构定义
typedef struct StackNode{
SElemType data;
struct SNode *next;
}StackNode, *LinkStack;
LinkStack S;
使用条件:不清楚栈元素数目
注意:链栈用无头结点的单链表表示。栈名指针S指向栈顶元素,而顺序栈栈顶指针指向第一个空位置。
4.2基本操作
5.队列
5.1存储结构定义
typedef struct {
QueuePtr front;
QueuePtr rear;
}LinkQueue;
5.2基本操作
5.2.1初始化
Status InitQueue(LinkQueue& Q) {
Q.front = Q.rear = (QNode*)malloc((sizeof * (QNode));
if (!Q.front)
exit OVERFLOW;
Q.front->next = NULL;
return OK;
}
头指针和头结点
5.2.2销毁
Status DestroyQueue(LinkQueue& Q) {
QueuePtr p = Q.front, postp;
while (p) {
postp=p->next
free(p);
p=postp;
}
Q.front = NULL;
Q.rear = NULL;
return OK;
}
代码有问题
清空要保留头节点,类比单链表操作
p=postp:pq指向同一位置,共享同一段内存
5.2.3入队
Status EnQueue(LinkQueue& Q, QElemType e) {
QueuePtr p;
p = (QNode*)malloc(sizeof * (QNode));
if (!p)
exit OVERFLOW;
p->data = e;
p->next = NULL;
Q.rear->next = p;
Q.rear = p;
return OK;
}
入队的节点的指针域记得赋空。
Q.rear->next = p; 尾指针是要不断往后移动的,尾指针的指针域链接新入队的节点,让p入队
Q.rear = p; 尾指针指向最新的节点
5.2.4出队
Status DeQueue(LinkQueue& Q, QElemType& e) {
if (Q.front == Q.rear)
return ERROR;
QueuePtr p = Q.front->next;
e = p->data;
Q.front->next = p->next;
if (Q.rear == p)
Q.rear = Q.front;
return OK;
}
只1个结点时改尾指针
6.循环队列
Q.base[Q.rear] = e;
Q.base 指向动态分配的数组中的元素。