线性结构之顺序栈、链栈、循环顺序队、链队(C语言实现)

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");
}

总结:以上几种逻辑结构,链栈、链队的实现建立在链表的基础上、大部分操作十分类似,无须多花费功夫,而值得留意的是循环顺序队的实现。

猜你喜欢

转载自blog.csdn.net/weixin_48394650/article/details/114647599