栈
栈是限定仅在表尾进行插入和删除操作的线性表
顺序栈
结构定义
typedef int SElenType //先假设为int类型
typedef struct
{
SElemType data[MAXSIZE];
int top;
}Sqstack;
进栈操作
Status Push(Sqstack *S,SElemType e)
{
if(S->top==MAXSIZE-1)
return error; //栈满
S->top++; //先让top加1
S->data[S->top]=e; //赋值
return OK;
}
出栈操作
Status Pop(Sqstack *S,SElemType *e)
{
if(S->top==-1) // 空栈
return error;
*e=S->data[S->top]; //赋值
S->top--; //指针减1
return OK;
}
两栈共享空间
结构定义
typedef struct
{
SElemType data[MAXSIZE];
int top1;
int top2;
}SqDoubleStack
定义一个大小为n的数组,数组两边分别作为两个栈的栈底。对于push 和pop操作,要区别是那个栈进出,应该增设一个变量stackNumber
Status Push(SqDoubleStack *S, SElemType e, int stackNumber)
{
if(S->top1==S->top2) //栈满,不能在push元素
return error;
if(StackNumber==1) //栈1 栈1是数组为0开始的哪一端
S->data[++S->top1]=e;
else if(stackNumber==2) //栈2
S->data[--S->top2]=e;
return OK;
}
Status Pop(SqDoubleStack *S, SElemType *e, int stackNumber)
{
if(stackNumber==1)
{
if(S->top1==-1) //栈空
return error;
*e=S->data[S->top1--]; //赋值并且自减
}
if(stackNumber==2)
{
if(S->top2==MAXSIZE) //栈满,栈1占完了
return error;
*e=S->data[S->top2++]; //赋值并且自加
}
return OK;
}
使用这样的数据结构,通常都是两个栈的空间需求有相反关系时,即一个栈增长,一个缩短的情况。
链栈
结构代码
typedef struct StackNode
{
SElemType data;
struct StackNode *next;
}StackNode,*LinkStackPtr; //定义结点
typedef struct LinkStack
{
LinkStackPtr top; //仅仅是定义一个指向结点的top指针
int count; //链表长度
}LinkStack;
进栈操作
Status Push(LinkStack *S,SElemType e)
{
LinkStackPtr p;
p=(LinkStackPtr)malloc(sizeof(StackNode))
p->data=e;
p->next=S->top;//注意栈的链式存储和单链表的区别,二者的指针方向是相反的
S->top=p;
S->count++;
}
出栈操作
Status Pop(LinkStack *S,SElemtType *e)
{
LinkStackPtr q;
if(StackEmpty(*S)) //空栈
return error;
*e=S->top->data;
p=S->top; //p中间变量用于释放空间
S->top=S->top->next;
free(p);
S->count--;
return OK;
}
递归
一个直接调用自己或通过一系列的调用语句间接调用自己的函数,称做递归函数。
每个递归定义必须至少有一个条件,满足时递归不再进行,即不再引用自身而是返回值推出。
队列
队列时只允许在一端进行插入操作,而在另一端进行删除操作的线性表。
允许插入的一端称为队尾,允许删除的一端称为队头。
循环队列
队列头尾相接的顺序存储结构称为循环队列
front指针指向对头元素,rear指针指向队尾元素的下一个位置。规定数组还有一个空闲的单元的时候,队列就满了。队列满的条件为 (rear+1)%QueueSize==front
计算队列长度的公式为 (rear-front+QueueSize)%QueueSize
顺序存储结构代码
typedef int QElemType
typedef struct
{
QElemType data[MAXSIZE];
int front;
int rear;
}SqQueue;
循环队列初始化代码
Status initqueue(SqQueue * Q)
{
Q->front=0;
Q->rear=0;
return OK;
}
队列求长度
int queuelength(SqQueue Q)
{
return (Q.rear-Q.front+MAXSIZE)%MAXSIZE;
}
循环队列入队操作
Status enqueue(SqQueue *Q, QElemType e)
{
if((Q.rear+1)%QueueSize==Q->front)//判断是否队满
return error;
Q->data[Q->rear]=e;
Q->rear=(Q->rear+1)%MAXSIZE; //rear向后移动一位,若到最后则转到头部
}
出队操作
Status dequeue(SqQueue *Q,QElemType *e)
{
if(Q->front==Q->rear) //判断是否队空
return error;
*e=Q->data[front];
Q->front=(Q->front+1)%MAXSIZE; //front向后移动一位,若到最后则转到头部
return OK;
}
链队列
队列的链式存储结构,其实就是线性表的单链表,只不过它只能尾进头出。
为了操作方便,我们将队头指针指向链队列的头结点,队尾指针则指向终结端点。空队列时,front 和 rear 都指向头结点。
代码结构
typedef int QElemType
typedef struct QNode
{
QElemType data;
struct QNode *next;
}QNode,*QueuePtr
typedef struct
{
QueuePtr front,rear;
}LinkQueue;
入队操作
Status enqueue(LinkQueue * Q, QElemType e)
{
QueuePtr a=(QueuePtr)malloc(sizeof(QNode))//分配结点a
if(!a) //分配失败
exit(OVERFLOW);
a->data=e; //赋值
a->next=NULL;
Q->rear->next=a;//把拥有元素e的新节点赋值给原队尾结点的后继
Q-rear=a; //更新rear
return OK;
}
出队操作
Status Dequeue(LinkQueue * Q, QElemType *e)
{
QueuePtr p;
if(Q->front==Q->rear)
return error; //队空
p=Q->front->next;//将要删除的队头结点暂存给p
*e=p->data;//赋值
Q->front->next=p->next;
if(Q->rear==p) //若队头是队尾,即只有一个元素时,则把rear指向头结点
Q->rear=Q->front;
free(p);
return OK;
}