数据结构——栈和队列(铁砂掌内功)

目录

前言

一、栈

1.1:栈的基本概念 

1.2:栈的格式         

 1.3:栈的实现

二、队列

1.1:队列的基本概念

 1.1.1:队列的基本结构

2.1:队列的实现


前言

        今天我们来修炼内功,一个厉害的武学宗师一点是内外兼修的。

        栈和队列本身在数据结构中作用不是很大,但是它常常在更为复杂的数据结构中作为分支使用。所以懂得栈和队列是很重要的,它是在为后面更为复杂的数据结构打基础的。


提示:以下是本篇文章正文内容,下面案例可供参考

一、栈

1.1:栈的基本概念 

        栈是常见的数据结构,只允许在固定的一端进行插入和删除元素操作。这一端为栈顶,另一端为栈底,插入数据和删除数据的操作。遵循后进先出原则。插入操作被称为入栈(压栈),入数据在栈顶,删除数据叫做出栈出数据也在栈顶。

        入栈顺序是 1,2,3,4 出栈顺序可以为4,3,2,1或先进4出4,进3出3,进2出2,进1出1。它也可以进4,3出4,在进2出2,再出3,进1出1。我们可以将最后一个进来的数据当作栈顶,当栈顶的数据出去以后,原先栈顶的原始就变成了栈顶数据,它就可以出去了。

1.2:栈的格式         

        栈可以用顺序表储存,链表储存,我们这里用的是动态顺序表储存。数组储存是静态顺序表的栈,而动态顺序表是动态的栈 。

typedef int sta_type;

typedef struct stack
{
	sta_type* a; //数组
	int top; //数组下标
	int capacity; //数组容量大小
}st;

 1.3:栈的实现

        栈很简单的,无非就一个增加数据和删除数据 ,以及对栈的初始化,和顺序表意义就是扩展几个空间。其实现方法和顺序表一样,懂了顺序表就可以很容易的看懂。

 动态顺序表的本质就是模仿实现数组       

void st_init(st* p) //初始化
{
	assert(p); //结构体首先不能为空
	p->a = malloc(sizeof(sta_type) * 4); //给它四个类型的空间
	if (p->a == NULL)
	{
		perror("malloc fail");
		return;
	}
	p->capacity = 4; //数组(指针)容量的大小
	p->top = 0; //栈顶元素下一个位置的元素 ,即下标
    // p->top = -1;    //这里表示栈顶元素
    // 这是因为当他放元素的时候top的元素是放在下一个地方
}

void st_push(st* p, sta_type x) //插入
{
	assert(p);
	if (p->top == p->capacity)
	{
		sta_type* tmp = (sta_type*)realloc(p->a, sizeof(sta_type)* p->capacity*2); // 扩容到当前数组的二倍
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		p->a = tmp; //根据realloc的特性,直接将地址赋予p其数组也被保存
		p->capacity *= 2;
	}
	p->a[p->top] = x;
	p->top++;
}

void st_pop(st* p) //删除 
{
	assert(p);
	assert(! st_empty(p));
	p->top--;
}

int st_size(st* p)    //
{
	assert(p);
	return p->top;
}

bool st_empty(st* p)
{
	assert(p);
	return p->top == 0; //当top是0为空
}

void st_destroy(st* p) //释放内存
{
	assert(p);
	free(p->a);
	p->a = NULL;
	p->capacity = 0;
	p->top = 0;
}

sta_type st_top(st* p) //访问栈顶元素
{
	assert(p);
	assert(!st_empty(p));
	return p->a[p->top - 1];    // 这里是因为前面top为0表示栈顶元素的下一个,所以要减1
}

二、队列

1.1:队列的基本概念

        队列是只允许在一端进行插入数据,在另一端删除数据的特殊性表,队列的特性是先进先出(FIFO)。插入数据一端叫做队尾出数据的一端叫队头。

 1.1.1:队列的基本结构

        对于队列我们用单链表表示。并且用尾插进行实现。 

typedef int q_type;

typedef struct queue_node	// 链表结构
{
	struct queue_node* next;
	q_type	data;
}q_node;

typedef struct queue	//队列结构
{
	q_node* head;	//队头
	q_node* tail;	//队尾
	int size;		//数据数量
}queue;

2.1:队列的实现

        只要懂得单链表的尾插和头删,下面的代码就很容易实现。首先根据上面的结构对队列进行初始化,初始化没有数据头和尾都为空。

        入队列就是尾插,不过有两种情况,队列没有数据的时候,和队列有数据的时候。没有数据在第一个数据插入的时候头尾都是一个数据。其余不变。

        出队列就是头删,也就考虑两种情况,一种是只有一个数据,在只有一个数据的时候释放这个数据,将头尾都指向NULL即可。另种是多个元素正常头删即可。

void QueueInit(queue* p)// 初始化队列
{
	assert(p);
	p->head = p->tail = NULL;
	p->size = 0;
}

void QueuePush(queue* p, q_type x)// 队尾入队列
{
	// 这里用的尾插
	assert(p);
	q_node* new = (q_node*) malloc(sizeof(q_node));
	if(new == NULL)
	{
		perror("malloc fail");
		return;
	}
	new->data = x;
	new->next = NULL;
	if (p->head == NULL)
	{
		p->head = p->tail = new;
	}
	else
	{
		p->tail->next = new;
		p->tail = new;
	}
	p->size++;
}

void QueuePop(queue* p)// 队头出队列
{
	assert(p);
	assert(p->head != NULL);
	q_node* del = p->head;
	if (del->next == NULL)
	{
		free(p->head);
		p->head = p->tail = NULL;
	}
	else
	{
		p->head = del->next;
		free(del);
		del->next = NULL;
	}
	p->size--;
}

bool QueueEmpty(queue* p)// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
{
	assert(p);
	return p->head = p->tail = NULL;
}

q_type QueueFront(queue* p)// 获取队列头部元素
{
	assert(p);
	assert(!QueueEmpty(p));
	return p->head->data;
}

q_type QueueBack(queue* p)// 获取队列队尾元素
{
	assert(p);
	assert(!QueueEmpty);
	return p->tail->data;
}

void QueueSize(queue* p)// 获取队列中有效元素个数 
{
	assert(p);
	return p->size;
}

void QueueDestroy(queue* p)// 销毁队列
{
	assert(p);
	q_node* cur = p->head;
	while (cur)
	{
		q_node* next = cur->next;
		free(cur);
		cur = next;
	}
	p->head = p->tail = NULL;
	p->size = 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值