功能相反的栈与队列

目录

一、栈

       介绍

       初始准备

       栈的初始化与销毁

       栈为空

       进栈与出栈

       栈的有效数据个数

       栈顶的数据

       全部代码

二、队列

       介绍

       初始准备

       队列的初始化与销毁

       队列为空

       进队列与出队列

       队列的有效数据个数

       队头和队尾的数据

       全部代码


一、栈

介绍

栈是一种线性结构,类似于链表和顺序表,但也有它的独特之处,只能栈顶入,栈顶出,所以栈也是“先进后出”或者“后进先出”

栈能采用链式结构也能采用数组结构来实现,这里采用数组结构

链式结构

采用单链表,头作栈顶,头插入数据,头删出数据

 

采用带头双链表,尾作栈顶,尾插入数据,尾删出数据

功能相反的栈与队列_第1张图片

数组结构

尾部作栈顶,头部作栈底,尾插入数据,尾删出数据

 

初始准备

为了使存储的数据类型不固定,能够在存储其它类型数据时容易修改,所以用typedef修改类型名

然后得建立一个结构体,有三个成员,一个是动态数组的起始地址(指针),另一个是栈顶变量,用来取出栈顶数据、判断是否还有空间时使用和有效数据个数,还有一个是数组容量 

用typedef将其类型名修改,使其简洁方便使用

功能相反的栈与队列_第2张图片

栈的初始化与销毁

将其三个成员初始化,指针置空,其余两个置为0即可

功能相反的栈与队列_第3张图片

销毁栈时,和初始化栈类似,只是多加了个free来释放空间,放置内存泄漏

功能相反的栈与队列_第4张图片 

栈为空

这里采用bool类型,判断栈是否为空,为真就是空,为假就是有数据

注意:在C中使用bool类型要引用头文件stdbool.h

 

进栈与出栈

入数据得先判断是否有空间,没有就增容,一般是扩为原来的2倍,避免频繁扩容

功能相反的栈与队列_第5张图片

然后再添加数据

删除数据时,得先判断栈是否为空,否则一直出,就容易出错,采用断言较好

 

栈的有效数据个数

有效数据就是top的大小,因为top从0开始,每次添加数据就+1

 

栈顶的数据

取出栈顶数据时,得先判断栈是否为空,采用断言较好

由于有效数据个数比其下标大1,所以要-1

全部代码

//头文件
#pragma once
#include
#include
#include
#include

typedef int DataType;

typedef struct Stack
{
	DataType* a;
	int top;
	int capacity;
}ST;

//初始化栈
void STInit(ST* ps);
//入栈
void STPushTop(ST* ps, DataType x);
//出栈
void STPopTop(ST* ps);
//栈顶数据
DataType STTop(ST* ps);
//有效数据个数
int STDataSize(ST* ps);
//销毁栈
void STDestroy(ST* ps);
//栈为空
bool STEmpty(ST* ps);

//定义文件
#include"Stack.h"

void STInit(ST* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->top = 0;
	ps->capacity = 0;
}

void STPushTop(ST* ps, DataType x)
{
	assert(ps);
	if (ps->top == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		DataType* ptr = (DataType*)realloc(ps->a, sizeof(DataType) * newcapacity);
		if (ptr == NULL)
		{
			printf("realloc fail\n");
			exit(-1);
		}
		ps->a = ptr;
		ps->capacity = newcapacity;
	}
	ps->a[ps->top] = x;
	ps->top++;
}

void STPopTop(ST* ps)
{
	assert(ps);
	assert(!STEmpty(ps));
	ps->top--;
}

bool STEmpty(ST* ps)
{
	assert(ps);
	return ps->top == 0;
}

DataType STTop(ST* ps)
{
	assert(ps);
	assert(!STEmpty(ps));
	return ps->a[ps->top - 1];
}

int STDataSize(ST* ps)
{
	assert(ps);
	return ps->top;
}

void STDestroy(ST* ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->top = 0;
	ps->capacity = 0;
}

//测试文件
#include"Stack.h"

void test1()
{
	ST st;
	STInit(&st);
	STPushTop(&st, 1);
	STPopTop(&st);
	printf("%d ", (&st)->a[(&st)->top]);
	STPushTop(&st, 2);
	STPopTop(&st);
	printf("%d ", (&st)->a[(&st)->top]);
	STPushTop(&st, 3);
	STPopTop(&st);
	printf("%d ", (&st)->a[(&st)->top]);
	STPushTop(&st, 4);
	STPopTop(&st);
	printf("%d ", (&st)->a[(&st)->top]);
	STPushTop(&st, 5);
	STPopTop(&st);
	printf("%d ", (&st)->a[(&st)->top]);
	STPushTop(&st, 6);
	STPopTop(&st);
	printf("%d ", (&st)->a[(&st)->top]);
	STDestroy(&st);
}
void test2()
{
	ST st;
	STInit(&st);
	STPushTop(&st, 1);
	STPushTop(&st, 2);
	STPushTop(&st, 3);
	STPushTop(&st, 4);
	printf("%d\n", STTop(&st));
	STDestroy(&st);
}
int main()
{
	test1();
	//test2();
	return 0;
}

二、队列

介绍

队列也是一种线性结构,类似于链表和顺序表,但也有它的独特之处,只能队尾入,队头出,所以队列也是“先进先出”或者“后进后出” 

由于用数组结构实现队列不太方便,效率不高,无论是数组开头作队头,还是数组尾作队头,都要挪动数据

数组开头作队头,数组尾作队尾,入数据方便,但得从数组开头出数据,即头删,需要往前挪动数据,比较麻烦  

功能相反的栈与队列_第6张图片 

数组开头作队尾,数组尾作队头,入数据得从数组开头入,即头插,需要往后挪动数据,很麻烦,出数据方便

功能相反的栈与队列_第7张图片

所以采用链式结构较好,这里采用单链表实现

初始准备

为了使存储的数据类型不固定,能够在存储其它类型数据时容易修改,所以用typedef修改类型名

然后得创建一个结构体,有2个成员,一个用来存储数据,另一个用来存储下一个数据的地址 

功能相反的栈与队列_第8张图片

为了方便进队列和出队列,所以定义了两个指针,一个指向头节点,另一个指向尾节点,用结构体的形式将二者封装在一起

功能相反的栈与队列_第9张图片

 队列的初始化与销毁

将第二个结构体的两个指针置为空即可

 

销毁队列时,得从头节点遍历,一个一个用free释放,最后再将头指针和尾指针置空即可

功能相反的栈与队列_第10张图片

队列为空

判断队列是否为空,只需判断头指针是否为空即可,依然采用bool类型

进队列与出队列

入数据进队列时,得先用malloc开辟空间,然后进行判断是否开辟成功,再然后就是对其成员赋值,得分两种情况

功能相反的栈与队列_第11张图片

第一种是第一次入数据进队列,直接作头节点

功能相反的栈与队列_第12张图片

 第二种则是在队列尾后链接节点

功能相反的栈与队列_第13张图片

出数据时也得考虑队列是否为空,不能一直出数据,否则取数据时会出现随机值,采用断言判断

出数据时还得考虑一种情况,就是删除最后一个数据时,得将尾指针置空,要不然会出现野指针 

功能相反的栈与队列_第14张图片 

队列的有效数据个数

由于队列是单链表实现的,所以只能采用从头节点开始遍历计数的方法

功能相反的栈与队列_第15张图片

 队头和队尾的数据

 由于已经定义了头和尾两个指针,所以直接访问即可,只是要判断队列是否为空

 

  全部代码

//头文件
#include
#include
#include
#include

typedef int DataType;

typedef struct QueueNode
{
	DataType data;
	struct QueueNode* next;
}QueueNode;

typedef struct Queue
{
	QueueNode* head;
	QueueNode* tail;
}Queue;

//初始化队列
void QueueInit(Queue* pq);
//销毁队列
void QueueDestroy(Queue* pq);
//尾部插入
void QueuePushBack(Queue* pq, DataType x);
//头部删除
void QueuePopFront(Queue* pq);
//头部数据
DataType QueueTop(Queue* pq);
//尾部数据
DataType QueueTail(Queue* pq);
//队列为空
bool QueueEmpty(Queue* pq);
//链表数据个数
int QueueSize(Queue* pq);

//定义文件
#include"Queue.h"

void QueueInit(Queue* pq)
{
	assert(pq);
	pq->head = NULL;
	pq->tail = NULL;
}

void QueuePushBack(Queue* pq, DataType x)
{
	assert(pq);
	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
	if (newnode == NULL)
	{
		printf("malloc fail\n");
		exit(-1);
	}
	newnode->next = NULL;
	newnode->data = x;
	if (pq->head == NULL)
	{
		pq->head = newnode;
		pq->tail = pq->head;
	}
	else
	{
		pq->tail->next = newnode;
		pq->tail = newnode;
	}
}

void QueuePopFront(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	QueueNode* Next = pq->head->next;
	if (pq->head == pq->tail)
	{
		pq->tail = NULL;
	}
	free(pq->head);
	pq->head = Next;
}

bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->head == NULL;
}

DataType QueueTop(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->head->data;
}

DataType QueueTail(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->tail->data;
}

int QueueSize(Queue* pq)
{
	assert(pq);
	QueueNode* cur = pq->head;
	int count = 0;
	while (cur)
	{
		count++;
		cur = cur->next;
	}
	return count;
}

void QueueDestroy(Queue* pq)
{
	assert(pq);
	QueueNode* cur = pq->head;
	while (cur)
	{
		QueueNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->head = NULL;
	pq->tail = NULL;
}

//测试文件
#include"Queue.h"

void test1()
{
	Queue q;
	QueueInit(&q);
	QueuePushBack(&q, 1);
	QueuePushBack(&q, 2);
	QueuePushBack(&q, 3);
	QueuePushBack(&q, 4);
	QueuePushBack(&q, 5);
	QueuePopFront(&q);
	QueuePopFront(&q);
	QueuePopFront(&q);
	QueuePopFront(&q);
	//QueuePopFront(&q);
	//QueuePopFront(&q);
	
	QueueNode* cur = (&q)->head;
	while (cur)
	{
		printf("%d ", cur->data);
		cur = cur->next;
	}
	QueueDestroy(&q);
}
void test2()
{
	Queue q;
	QueueInit(&q);
	QueuePushBack(&q, 1);
	QueuePushBack(&q, 2);
	QueuePushBack(&q, 3);
	QueuePushBack(&q, 4);
	DataType top = QueueTop(&q);
	printf("%d ", top);
	QueuePopFront(&q);
	top = QueueTop(&q);
	printf("%d ", top);
	printf("\n");

	DataType tail = QueueTail(&q);
	printf("%d ", tail);
	printf("\n");

	int sz = QueueSize(&q);
	printf("%d\n",sz);
	QueuePopFront(&q);
	sz = QueueSize(&q);
	printf("%d\n", sz);
	QueueDestroy(&q);
}
int main()
{
	test1();
	//test2();
	return 0;
}

你可能感兴趣的:(数据结构,链表)