栈与队列是两种重要的数据结构,有着广泛的应用,他们可以通过对链表功能加以限制改造而来。栈是一种先进后出(FILO)的数据结构,只能在一头进行加入删除,而队列是一种先进先出(FIFO)的数据结构,一头只能加入,另一头只能删除。
栈的实现:
# include <stdio.h>
# include <malloc.h>
# include <stdlib.h>
typedef struct Node
{
int data;
struct Node * pNext;
}NODE, * PNODE;
typedef struct Stack
{
PNODE pTop;
PNODE pBottom;
}STACK, * PSTACK;
//函数声明
void init_stack(PSTACK); //创建一个空栈
void push_stack(PSTACK, int); //压栈
void traverse_stack(const PSTACK); //遍历输出
bool empty_stack(PSTACK); //判断栈是否为空
bool pop_stack(PSTACK, int *); //出栈
bool clear_stack(PSTACK); //将栈清空
int main(void)
{
STACK s;
int val;
init_stack(&s);
push_stack(&s, 1);
push_stack(&s, 2);
push_stack(&s, 78);
push_stack(&s, 499);
push_stack(&s, 97);
push_stack(&s, 134);
traverse_stack(&s);
pop_stack(&s, &val);
/*
if( pop_stack(&s, &val) ) //如果将if语句写在这里,if中的判断式已经执行过一次,即出栈一次,会造成bug。
{
printf("出栈成功,出栈的元素值为:%d\n", val);
}
else
{
printf("出栈失败!\n");
}
*/
traverse_stack(&s);
printf("清空栈!\n");
clear_stack(&s);
traverse_stack(&s);
return 0;
}
void init_stack(PSTACK pS)
{
pS->pTop = (PNODE)malloc(sizeof(NODE));
if (NULL == pS->pTop)
{
printf("内存分配失败!\n");
exit(-1);
}
else
{
pS->pBottom = pS->pTop;
pS->pTop->pNext = NULL;
}
return;
}
void push_stack(PSTACK pS, int val)
{
PNODE pNew = (PNODE)malloc(sizeof(NODE));
if (NULL == pNew)
{
printf("压栈内存分配失败!\n");
return;
}
pNew->data = val;
pNew->pNext = pS->pTop;
pS->pTop = pNew;
return;
}
void traverse_stack(const PSTACK pS)
{
PNODE p = pS->pTop;
if ( empty_stack(pS) )
{
printf("输出失败,栈为空!\n");
}
else
{
printf("栈中的元素为:\n");
while (p != pS->pBottom)
{
printf("%d\t", p->data);
p = p->pNext;
}
printf("\n");
}
return;
}
bool empty_stack(PSTACK pS)
{
if(pS->pTop == pS->pBottom)
return true;
else
return false;
}
bool pop_stack(PSTACK pS, int * pVal)
{
if ( empty_stack(pS) )
{
printf("栈为空,出栈失败!\n");
return false;
}
else
{
PNODE p = pS->pTop;
*pVal = p->data;
pS->pTop = p->pNext;
printf("出栈成功,出栈的元素值为:%d\n", p->data);
free(p);
p = NULL;
return true;
}
}
bool clear_stack(PSTACK pS)
{
if ( empty_stack(pS) )
{
printf("栈为空,无法清空!\n");
return false;
}
else
{
PNODE p, q;
p = pS->pTop;
while (pS->pBottom != p)
{
q = p->pNext;
free(p);
p = q;
}
pS->pTop = pS->pBottom;
}
return true;
}
循环队列
顺序队列有一个先天不足, 那就是空间利用率不高, 会产生”假溢出”现象,即:其实队列中还有空闲的空间以存储元素, 但我们在判断队列是否还有空间时, 队列告诉我们队列已经满了, 因此这种溢出并不是真正的溢出, 在data数组中依然存在可以放置元素的空位置, 所以说这是一种”假溢出”;
于是我们就引入了循环队列的概念, 将顺序队列臆造为一个环状的空间, 即把存储队列元素的表从逻辑上看成一个环, 称为循环队列,其示意图如下:
注意:如图中所示,我们的循环队列为了在实现上的便利, 会有一个位置的空闲, m_front(如图中的front)指针总会指向一个元素值为空的位置,因此(m_front+1)%capacity才真正的指向队首元素, 而m_rear(图中为rear)才指向一个真实存在的队尾元素;
循环队列的实现:
# include <stdio.h>
# include <malloc.h>
typedef struct Queue
{
int * pBase;
int front;
int rear;
}QUEUE;
void init(QUEUE *); //队列初始化
bool en_queue(QUEUE *, int); //入队
void traverse_queue(QUEUE *); //遍历队列
bool is_full(QUEUE *); //判断队列是否为满
bool is_empty(QUEUE *); //判断队列是否为空
bool out_queue(QUEUE *, int *); //出队
int main(void)
{
QUEUE Q;
int val;
init(&Q);
en_queue(&Q, 1);
en_queue(&Q, 2);
en_queue(&Q, 3);
en_queue(&Q, 4);
en_queue(&Q, 5);
en_queue(&Q, 6);
en_queue(&Q, 7);
en_queue(&Q, 8);
traverse_queue(&Q);
out_queue(&Q, &val);
out_queue(&Q, &val);
traverse_queue(&Q);
return 0;
}
void init(QUEUE * pQ)
{
pQ->pBase = (int *)malloc(sizeof(int)*6);
pQ->front = 0;
pQ->rear = 0;
}
bool en_queue(QUEUE * pQ, int val)
{
if (is_full(pQ))
{
printf("入队失败,队列已满!\n");
return false;
}
else
{
pQ->pBase[pQ->rear] = val;
pQ->rear = (pQ->rear+1)%6;
return true;
}
}
bool is_full(QUEUE * pQ)
{
if ((pQ->rear+1)%6 == pQ->front)
return true;
else
return false;
}
void traverse_queue(QUEUE *pQ)
{
int i = pQ->front;
printf("队列元素为:\n");
while(i != pQ->rear)
{
printf("%d ", pQ->pBase[i]);
i = (i+1)%6;
}
printf("\n");
}
bool out_queue(QUEUE * pQ, int * pVal)
{
int val;
if (is_empty(pQ))
{
printf("出队失败,队列为空!\n");
return false;
}
else
{
*pVal = pQ->pBase[pQ->front];
val = pQ->pBase[pQ->front];
pQ->front = (pQ->front + 1) % 6;
printf("出队成功,出队的元素是:%d\n", val);
return true;
}
}
bool is_empty(QUEUE * pQ)
{
if (pQ->front == pQ->rear)
{
return true;
}
else
{
return false;
}
}