1、顺序栈
/*
顺序栈,就是用一组地址连续的存储单元来存放栈元素,然后用一个栈结构去维护一个
栈。在C中,可用动态开辟的数组去表示,维护的栈结构需要有一个栈底和一个栈顶指针。
因为开辟一个数组需要事先知道它的大小,所以栈结构里就必须还有一个整型变量来表示
当前栈的存储容量(stacksize)。实现如下:
*/
#include <stdio.h>
#include <windows.h>
/*
用顺序表实现一个顺序栈
*/
//定义一个顺序栈
#define MAXSIZE 100
typedef int ElemType;
typedef struct SqStack {
ElemType* base; //在栈构造之前和销毁之后,base的值为NULL
ElemType* top; //栈顶指针
int stacksize; //当前已分配的存储空间,以元素为单位
}SqStack;
void InitStack(SqStack* S);//创建一个顺序表
int StackLen(SqStack S);//计算当前栈的容量
bool StackEmpty(SqStack* S);//判断是否栈空
bool StackFull(SqStack* S);//判断是否栈满
bool Push(SqStack* S, ElemType e);//入栈操作,e为入栈的值
bool Pop(SqStack* S, ElemType* e);//出栈操作,e返回出栈的值
bool GetTop(SqStack* S, ElemType* e);//取栈顶元素
bool ClearStack(SqStack* S);//清空一个栈
bool DestroyStack(SqStack* S);//销毁一个栈
//main() 负责测试
int main() {
SqStack s1;
ElemType e;
InitStack(&s1);
//入栈
for (int i = 0; i < 5; ++i) {
Push(&s1, i + 1);
}
//出栈,并输出当前出栈的值
int len = StackLen(s1);
for (int i = 0; i < len; ++i) {
Pop(&s1, &e);
printf("%d ", e);
}
printf("\n");
/*
//销毁当前栈
bool isDestory = DestroyStack(&s1);
printf("当前顺序栈是否已销毁? %d", isDestory);
*/
DestroyStack(&s1);
//!s1.base 等价于 NULL == s1.base
if (!s1.base) {
printf("当前顺序栈已销毁!\n");
}
system("pause");
return 0;
}
//创建一个顺序表
void InitStack(SqStack* S) {
S->top = (ElemType*)malloc(MAXSIZE * sizeof(ElemType));
if (!S->top) {
exit(0);
}
//栈顶指向栈底
S->base = S->top;
S->stacksize = MAXSIZE;
}
//计算当前栈的容量
int StackLen(SqStack S) {
return S.top - S.base;
}
//判断是否栈空
bool StackEmpty(SqStack* S){
if(S->top == S->base)
return true;
else
return false;
}
//判断是否栈满
bool StackFull(SqStack* S){
if(S->top - S->base == S->stacksize )
return true;
else
return false;
}
//入栈操作
bool Push(SqStack* S, ElemType e){
//判断栈是否已满
if (!StackFull(S)){
*(S->top)++ = e; //等价于 *S-> top = e; S->top++;
return true;
}
else{
return false;
}
}
//出栈操作
bool Pop(SqStack* S, ElemType * e){
//判断栈是否为空
if (!StackEmpty(S)) {
--S->top;
*e = *S->top;
return true;
}
else
return false;
}
//取栈顶元素
bool GetTop(SqStack* S, ElemType* e){
if(StackEmpty(S)) {
*e = *--S->top; //等价于 --S->top; *e = *S->top;
return true;
}
else{
return false;
}
}
//清空一个栈
bool ClearStack(SqStack* S){
if(StackEmpty(S)){
return true;
}
else{
S->top = S->base;
return true;
}
}
//销毁一个栈
bool DestroyStack(SqStack* S){
if(NULL != S->base){
free(S->base);
S->base = S->top = NULL;
S->stacksize = 0;
return true;
}
else{
//若NULL == S->base, 则说明栈并未构造或已被销毁,直接返回true
return true;
}
}
2、链栈
# 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; //PSTACK 等价于 struct STACK *
void init(PSTACK);
void push(PSTACK, int );
void traverse(PSTACK);
bool pop(PSTACK, int *);
void clear(PSTACK pS);
int main(void)
{
STACK S; //STACK 等价于 struct Stack
int val;
init(&S); //目的是造出一个空栈
push(&S, 1); //压栈
push(&S, 2);
push(&S, 3);
push(&S, 4);
push(&S, 5);
push(&S, 6);
traverse(&S); //遍历输出
clear(&S);
//traverse(&S); //遍历输出
if ( pop(&S, &val) )
{
printf("出栈成功,出栈的元素是%d\n", val);
}
else
{
printf("出栈失败!\n");
}
traverse(&S); //遍历输出
return 0;
}
void init(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; //pS->Bottom->pNext = NULL;
}
}
void push(PSTACK pS, int val)
{
PNODE pNew = (PNODE)malloc(sizeof(NODE));
pNew->data = val;
pNew->pNext = pS->pTop; //pS->Top不能改成pS->Bottom
pS->pTop = pNew;
return;
}
void traverse(PSTACK pS)
{
PNODE p = pS->pTop;
while (p != pS->pBottom)
{
printf("%d ", p->data);
p = p->pNext;
}
printf("\n");
return;
}
bool empty(PSTACK pS)
{
if (pS->pTop == pS->pBottom)
return true;
else
return false;
}
//把pS所指向的栈出栈一次,并把出栈的元素存入pVal形参所指向的变量中,如果出栈失败,返回false,否则返回true
bool pop(PSTACK pS, int * pVal)
{
if ( empty(pS) ) //pS本身存放的就是S的地址
{
return false;
}
else
{
PNODE r = pS->pTop;
*pVal = r->data;
pS->pTop = r->pNext;
free(r);
r = NULL;
return true;
}
}
//clear清空
void clear(PSTACK pS)
{
if (empty(pS))
{
return;
}
else
{
PNODE p = pS->pTop;
PNODE q = NULL;
while (p != pS->pBottom)
{
q = p->pNext;
free(p);
p = q;
}
pS->pTop = pS->pBottom;
}
}
3、循环顺序队
# include<stdio.h>
# include<malloc.h>
# include<stdlib.h>
# define MAXQSIZE 100
/*
用顺序表实现一个循环顺序队列,重点有4个。
1、为何会存在循环顺序队这一逻辑结构?
为了解决顺序队列假上溢的问题--引入循环队列
2、如何让一个线性表循环起来?
>>入队: Q->rear = (Q->rear + 1) % MAXQSIZE;
>>出队: Q->front = (Q->front + 1) % MAXQSIZE;
3、 如何判断队满?
>>另设一个标志以区别队满
>>另设一个变量,记录元素个数
>>少用一个元素空间(一般性选用)
(rear + 1) % MAXQSIZE == front;
4、如何求队列长度?☆☆☆
(Q->rear - Q->front + MAXQSIZE) % MAXQSIZE
*/
typedef int QElemtype;
typedef struct Queue{
QElemtype * base; //动态分配存储空间
int front; //头指针,若队列不空,指向队列头元素
int rear; // 尾指针,若队列不空,指向队列尾元素的下一个未知
}SqQueue;
bool initQueue(SqQueue * Q);
bool QueueEmpty(SqQueue * Q);
bool QueueFull(SqQueue * Q);
int QueueLength(SqQueue * Q);
bool EnQueue(SqQueue * Q, QElemtype e);
bool DeQueue(SqQueue * Q, QElemtype * e);
bool GetHead(SqQueue * Q, QElemtype * e);
void TraverseQueue(SqQueue * Q);
int main(void){
SqQueue Q;
QElemtype e;
if(initQueue(&Q))
printf("顺序队列初始化成功!\n");
else
printf("顺序队列初始化失败!\n");
printf("此顺序队列的长度为:%d\n", QueueLength(&Q));
for(int i = 0; i < 5; i++){
EnQueue(&Q, i);
}
printf("此顺序队列的长度为:%d\n", QueueLength(&Q));
// TraverseQueue(&Q);
for(int i = 0; i < 5; i++){
GetHead(&Q, &e);
DeQueue(&Q, &i);
printf("%d ", e);
}
printf("\n");
return 0;
}
//初始化
bool initQueue(SqQueue * Q){
Q->base = (QElemtype*)malloc(sizeof(QElemtype)*MAXQSIZE);
if(NULL == Q->base){
return false;
}
Q->front = Q->rear = 0;
return true;
}
//判断队空
bool QueueEmpty(SqQueue * Q){
if(Q->front == Q->rear)
return true;
else
return false;
}
//判断队满
bool QueueFull(SqQueue * Q){
if((Q->rear + 1) % MAXQSIZE == Q->front)
return true;
else
return false;
}
//长度
int QueueLength(SqQueue * Q){
if(QueueEmpty(Q))
return 0;
else
return ((Q->rear - Q->front + MAXQSIZE) % MAXQSIZE);
}
//入队
bool EnQueue(SqQueue * Q, QElemtype e){
if(QueueFull(Q))
return false;
else{
//Q->base[Q->rear++] = e;
Q->base[Q->rear] = e;
Q->rear = (Q->rear + 1) % MAXQSIZE;
return true;
}
}
//出队
bool DeQueue(SqQueue * Q, QElemtype * e){
if(QueueEmpty(Q))
return false;
else{
*e = Q->base[Q->front];
Q->front = (Q->front + 1) % MAXQSIZE;
return true;
}
}
//取队头元素
bool GetHead(SqQueue * Q, QElemtype * e){
if(QueueEmpty(Q))
return false;
else{
*e = Q->base[Q->front];
return true;
}
}
//遍历输出循环队列
void TraverseQueue(SqQueue * Q) {
int i = Q->front;
while( i != Q->rear){
printf("%d ", Q->base[i]);
i = (i + 1) % MAXQSIZE;
}
printf("\n");
}
4、链队
# include<stdio.h>
# include<malloc.h>
# include<stdlib.h>
# define MAXQSIZE 100
/*
用链表实现一个链队
*/
typedef int QElemtype;
typedef struct Qnote{
QElemtype data;
struct Qnote * next;
}QNode, * QueuePtr;
typedef struct Queue{
QueuePtr front;
QueuePtr rear;
}LinkQUEUE,* LinkQueue;
bool initQueue(LinkQueue Q);
bool QueueEmpty(LinkQueue Q);
bool QueueFull(LinkQueue Q);
int QueueLength(LinkQueue Q);
bool EnQueue(LinkQueue Q, QElemtype e);
bool DeQueue(LinkQueue Q, QElemtype * e);
bool GetHead(LinkQueue Q, QElemtype * e);
bool DestoryQueue(LinkQueue Q);
void TraverseQueue(LinkQueue Q);
int main(void){
LinkQUEUE Q;
if(initQueue(&Q)){
printf("顺序队列初始化成功!\n");
}
else{
printf("顺序队列初始化失败!\n");
}
printf("初始化后顺序队列的长度为:%d\n", QueueLength(&Q));
for(int i = 1; i <= 5; i++){
EnQueue(&Q, i);
}
printf("元素入队后顺序队列的长度为:%d\n", QueueLength(&Q));
TraverseQueue(&Q);
printf("\n");
return 0;
}
//初始化
bool initQueue(LinkQueue Q){
Q->front = Q->rear = (QueuePtr)malloc(sizeof(QNode));
if(NULL == Q->front){
// exit(-1);
return false;
}
else{
Q->front->next = NULL;
return true;
}
}
//判断队空
bool QueueEmpty(LinkQueue Q){
if(Q->front == Q->rear){
return true;
}
else{
return false;
}
}
//判断队满
bool QueueFull(LinkQueue Q){
//链队一般不会满,除非计算机内存不够...
}
//长度
int QueueLength(LinkQueue Q){
int len = 0;
QueuePtr p = Q->front->next;
while(NULL != p){
len++;
p = p->next;
}
return len;
}
//入队
bool EnQueue(LinkQueue Q, QElemtype e){
QueuePtr pNew = (QueuePtr)malloc(sizeof(QNode));
if(NULL == pNew){
// exit(-1);
return false;
}
else{
pNew->data = e;
pNew->next = NULL;
Q->rear->next = pNew;
Q->rear = pNew;
return true;
}
}
//出队
bool DeQueue(LinkQueue Q, QElemtype * e){
if(QueueEmpty(Q)){
return false;
}
else{
QueuePtr p = Q->front->next;
*e = p->data;
Q->front->next = p->next;
free(p);
p = NULL;
return true;
}
}
//取队头元素
bool GetHead(LinkQueue Q, QElemtype * e){
if(QueueEmpty(Q)){
return false;
}
else{
*e = Q->front->next->data;
return true;
}
}
bool DestoryQueue(LinkQueue Q){
QueuePtr p;
while(NULL != Q->front){
p = Q->front->next;
free(Q->front);
Q->front = p;
}
return true;
}
//遍历输出链队
void TraverseQueue(LinkQueue Q) {
QueuePtr p = Q->front->next;
while(NULL != p){
printf("%d ", p->data);
p = p->next;
}
printf("\n");
}
总结:以上几种逻辑结构,链栈、链队的实现建立在链表的基础上、大部分操作十分类似,无须多花费功夫,而值得留意的是循环顺序队的实现。