目录
1 顺序栈
栈的定义:作为一种限定性线性表,是将线性表的插入和删除运算限制为仅在表的一段进行。
表中允许插入和删除操作的一端称为栈顶(Top),表的另一端被称为栈底(Bottom)。
当栈中没有元素的时候称为空栈。
栈的插入操作成为进栈和入栈。
栈的删除操作成为出栈和退栈。
栈的特点:后进先出。
1.1 栈的存储结构:顺序栈和链栈
1.1.1 顺序栈
用顺序存储结构实现的栈,即利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素,同时由于栈的操作的特殊性,还必须附设一个位置指针 top(栈顶指针)来动态地指示栈顶元素在顺序栈中的位置。
通常以 top = -1 表示空栈。
顺序栈的创建
#define Stack_Size 50
typedef struct
{
StackElementType elem[Stack_Size];
int top;
}SeqStack;
栈的基本操作:
InitStack(S) 初始化:初始化一个新的栈。
Empty(S) 栈的非空判断:若栈 S 不为空,则返回TRUE;否则,返回FALSE。
IsFull(S) 栈的非满判断:若栈 S 为满,则返回TRUE;否则,返回FALSE。
Push(S,x) 入栈:在栈 S 的顶部插入元素 x ,栈满则返回FALSE;否则返回空元素NULL。
Pop(S) 出栈:若栈 S 不空,则返回栈顶元素,并从栈顶中删除该元素;否则返回空元素NULL。
GetTop(S) 取栈顶元素:若栈 S 不为空,则返回栈顶元素:否则返回空元素NULL。
SetEmpty(S) 置栈空操作:置栈 S 为空栈。
1.1 初始化
void InitStack(SeqStack* S)
{
S->top = -1;
}
1.2 判栈空
bool IsEmpty(SeqStack* S)
{
return (S->top == -1 ? true : false);
}
1.3 判栈满
bool IsFull(SeqStack* S)
{
return (S->top == Stack_Size - 1 ? true : false);
}
1.4 进栈
bool Push(SeqStack* S, StackElementType x)
{
if (S->top == Stack_Size - 1)
{
return false
}
s->top++;
S->elem[S->top] = x;
return true;
}
1.5 出栈
bool Pop(SeqStack* S, StackElementType* x)
{
if (S->top == -1)
{
return false;
}
*x = S->elem[S->top];
s->top--;
return true;
}
1.6 取栈顶
bool IntGetTop(SeqStack* S, StackElementType* x)
{
if (S->top == -1)
{
return false;
}
*x = S->elem[S->top];
return true;
}
2 双端栈
当程序里边有多个栈的时候,两栈共享空间。
利用栈,栈底位置不变,栈顶位置动态变化的特点。申请一个共享的一维数组空间 S[M],将两栈的栈底分别放在一维数组的两端,分别为 0,M-1。
双端栈结构的定义
#define M 100
typedef char StackElementType;
typedef struct
{
StackElementType Stack[M];
StackElementType top[2];
}DqStack;
注意:
操作时需要表明具体栈(top[0]还是top[1])
栈空判断
栈满判断 当两个栈迎面相遇才会溢出,即top[0]+top[1]
2.1 初始化
void InitStack(DqStack* S)
{ // 初始化
S->top[0] = -1;
S->top[1] = M;
}
2.2 进栈
bool Push(DqStack* S, StackElementType x, int i)
{
if (S->top[0] + 1 == S->top[1]) return false;
switch (i)
{
case 0:S->top[0]++;
S->Stack[S->top[0]] = x;
break;
case 1:S->top[1]--;
S->Stack[S->top[1]] = x;
break;
default:return false;
}
return true;
}
2.3 出栈
bool Pop(DqStack* S, StackElementType* x, int i)
{
switch (i)
{
case 0:if (S->top[0] == -1) return false;
*x = S->Stack[S->top[0]];
S->top[0]--;
break;
case 1:if (S->top[1] == M) return false;
*x = S->Stack[S->top[1]];
S->top[1]++;
break;
default:return false;
}
return true;
}
3 链栈
一般将链式存储的栈称为链栈,存储结构通常使用单链表。由于栈的特点,只能在栈顶进行插入和删除操作,所以链栈中,通常把单链表的表头做为栈顶,完成压栈,出栈操作。
链栈的创建
typedef char DataType;
typedef struct snode
{ //链栈的结构体与单链表的结构相同
DataType data;
struct snode* next;
}LSNode, * Linkstack;
//因为不需要头结点,所以要有结构体指针。
3.1 初始化
void InitStack(LinkStack* s)
{ //由于链栈不带头结点,因此只需要将栈顶指针s置空
*s = NULL;
}
3.2 判栈空
bool IsEmpty(LinkStack s)
{ //只要栈顶指针 s 指向空,栈就是空
if (s == NULL) return false;
else
{
return true;
}
}
3.3 入栈
bool Push(LinkStack* s, DataType x)
{ //在栈顶插入 x
LSNode* p;
p = (LSNode*)malloc(sizeof(LSNode));
p->data = x;
p->next = *s;
*s = p;
return true;
}
3.4 出栈
bool Pop(LinkStack* s, DataType* x)
{ //与顺序栈相同,出栈前先判断栈是否为空
//出站后释放原栈顶
LSNode* p;
if (s == NULL)
{
printf("栈空!");
return false;
}
p = *s;
*s = p->next;
*x = p->data;
free(p);
return true;
}
3.5 取栈顶
bool IntGetTop(LinkStack s, DataType* x)
{
if (s == NULL) return false;
*x = s->data;
return true;
}
4 队列
队列是一种只允许在表的一端进行插入操作,而在另一端进行删除操作的星星表。允许插入的一端叫做队尾,允许删除的一端叫队头。当队列没有元素叫做空队列。
每一次入队列的元素都放在原队尾数据元素之后成为新的队尾,每一次出队都是队头元素。
即:先入队的先出队。(先入先出)
初始化时,队头指针与队尾指针都指向空,在入队时,队尾指针指向最近入队的元素,队头指针指向第一个元素之前,在出队时,队头指针指向队头元素,队尾指针不变。
我们发现,当队列在出队操作后,在对头指针前空间不能再使用,因此采用循环队列。
我们又发现,队空与队满时,都是队头指针==队尾指针。
区分两者有三种办法:
1,少使用一个空间,当尾指针 rear+1=front 时,认为队满。
2,设置一个标志位 tag,初始位置 tag=0,入队成功 tag=1,出队成功 tag=0。
队满条件为:rear==front&tag==1
队空条件为:rear==front&tag==0
3,设置计数器 count,初始时设 count=0,每完成入队操作 count++,出队操作 count--。
队满条件为:count==0
队空条件为:count==Max
下面采用第三种方法。
循环队列结构的定义
typedef char DateType;
typedef struct
{
DateType quene[Max];
int front; //队头指针
int rear; //队尾指针
}SeqQueue;
队列的基本操作:
InitQueue(q) 初始化
InQueue(q,x) 队列 q 尾插元素 x ,成功返回true
OutQueue(q,x) 删除队首,返回其值,成功返回true
FrontQueue(q,x) 读对头,队不变
4.1 初始化
void InitQueue(SeqQuene* q)
{
q->front = 0;
q->rear = 0;
q->count = 0;
}
4.2 入队
bool InQueue(SeqQuene* q, DataType x)
{ //入队操作只需要判断是否队满
if (q->count == Max) return false;
q->queue[q->rear] = x;
q->rear=(q->rear+1)%Max; //队尾指针加 1
return true;
}
4.3 出队
bool OutQueue(SeqQuene* q, DataType* x)
{ //出队操作只需要判断是否队空
if (q->count == 0) return false;
*x = q->queue[q->front];
q->front = (q->front + 1) % Max;
return true;
}
4.4 取队头
bool FrontQueue(SeqQuene q, DataType* x)
{
if (q.count == 0) return false;
*x = q.queue[q.front];
return true;
}