数据结构与算法栈的实现(附源码)

Posted sukuni

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构与算法栈的实现(附源码)相关的知识,希望对你有一定的参考价值。

   

目录

一.栈的概念和结构

二.接口实现

A.初始化  Stackinit   销毁  Stackdestroy

1.Stackinit

2.Stackdestroy

B.插入 Stackpush  删除  Stackpop

1.Stackpush

2.Stackpop

C.出栈 Stacktop

D. 栈的有效元素  Stacksize  判空 Stackempty

1.Stacksize

2.Stackempty

三.源码

Stack.h

Stack.c

test.c


一.栈的概念和结构

1.一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作

2.进行数据插入和删除操作的一端称为栈顶,另一端称为栈底

3.栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则;

压栈:向栈中插入数据;

出栈:从栈中取出数据;

图示:

 

其实用链表和数组都可以实现栈,但栈底就相当于链表的头,数组的第一个元素,栈顶就相当与链表的尾,数组的最后一个元素,当我们进行压栈或是出栈操作时,链表就需要找到尾,所以时间复杂度为O(N),而数组则是O(1),所以这里选择用数组实现栈比较好

用数组实现的话,就和前面的顺序表类似了。

顺序表

二.接口实现

A.初始化  Stackinit   销毁  Stackdestroy

1.Stackinit

1.这里数组的初始化就和顺序表那里是一样的了,需要用到动态内存管理的函数,如果不懂的话,建议去补一下这一块的知识哦;

2.这个top用来记录实时数据的数量,和顺序表那里的 sz 是一样的,但注意:

  <1>  如果初始化成0,那么这个 top 就指的是栈顶的下一个位置;

  <2>  如果初始化成-1,那么这个 top 就指的是栈顶的位置;

3.初始化容量,这由你自己决定。

void Stackinit(Stack* ps)

	assert(ps);

	ps->arr = (STdatatype*)malloc(sizeof(STdatatype) * MR_CAP);
	if (ps->arr == NULL)
	
		perror("malloc fail");
		exit(-1);
	
	ps->top = 0;   //表示的是栈顶的下一个位置
	ps->capacity = MR_CAP;   //默认容量

2.Stackdestroy

这个非常简单,直接看代码吧。

void Stackdestroy(Stack* ps)

	assert(ps);

	free(ps->arr);
	ps->arr = NULL;
	ps->top = 0;
	ps->capacity = 0;

B.插入 Stackpush  删除  Stackpop

1.Stackpush

在插入前,我们需要判断容量是否已满,若已满,则需要扩容。

void Stackpush(Stack* ps, STdatatype x)

	assert(ps);
	if (ps->top == ps->capacity)   //判断是否已满
	
		STdatatype* tmp = (STdatatype*)realloc(ps->arr, 2 * sizeof(STdatatype) * ps->capacity);
		if (tmp == NULL)
		
			perror("realloc fail");
			exit(-1);
		
		ps->arr = tmp;
		ps->capacity *= 2;
	
	ps->arr[ps->top] = x;
	ps->top++;   //数据入栈后,实时数据数量加1

2.Stackpop

删除前要注意栈是否为空,若为空则不能进行删除操作;

删除就是使 top 减1。

void Stackpop(Stack* ps)

	assert(ps);
	assert(ps->top);   //判断栈是否为空

	ps->top--;  //删除数据

C.出栈 Stacktop

出栈前需要判断栈是否为空,为空则无数据可出栈;

因为前面初始化的 top 是0,所以栈顶数据的下标是 top-1 ,如果初始化的 top 是-1,那么栈顶数据的下标则是 top 。

STdatatype Stacktop(Stack* ps)

	assert(ps);
	assert(ps->top);  //判断栈是否为空
	return ps->arr[ps->top - 1];  //栈顶数据的下标是 top-1

D. 栈的有效元素  Stacksize  判空 Stackempty

1.Stacksize

1.若初始化的 top 是0,则 top 就是栈的有效元素个数;

2.若初始化的 top 是-1,则 top+1 为栈的有效元素个数。

int Stacksize(Stack* ps)

	assert(ps);

	return ps->top;

2.Stackempty

1.如果 top 是0,则为空,返回 true;

2.如果 top 不是0,则不为空,返回 false 。

bool Stackempty(Stack* ps)

	assert(ps);

	return ps->top == 0;  //如果 top ==0 ,则这句代码为真,返回 true;反之,返回 false

三.源码

Stack.h

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>

#define MR_CAP 5

typedef int STdatatype;

typedef struct Stack

	STdatatype* arr;
	int top;
	int capacity;
Stack;

void Stackinit(Stack* ps);

void Stackpush(Stack* ps,STdatatype x);

void Stackpop(Stack* ps);

STdatatype Stacktop(Stack* ps);

int Stacksize(Stack* ps);

bool Stackempty(Stack* ps);

void Stackdestroy(Stack* ps);

Stack.c

#include "Stack.h"

void Stackinit(Stack* ps)

	assert(ps);

	ps->arr = (STdatatype*)malloc(sizeof(STdatatype) * MR_CAP);
	if (ps->arr == NULL)
	
		perror("malloc fail");
		exit(-1);
	
	ps->top = 0;
	ps->capacity = MR_CAP;


void Stackpush(Stack* ps, STdatatype x)

	assert(ps);
	if (ps->top == ps->capacity)
	
		STdatatype* tmp = (STdatatype*)realloc(ps->arr, 2 * sizeof(STdatatype) * ps->capacity);
		if (tmp == NULL)
		
			perror("realloc fail");
			exit(-1);
		
		ps->arr = tmp;
		ps->capacity *= 2;
	
	ps->arr[ps->top] = x;
	ps->top++;


void Stackpop(Stack* ps)

	assert(ps);
	assert(ps->top);

	ps->top--;


STdatatype Stacktop(Stack* ps)

	assert(ps);
	assert(ps->top);
	return ps->arr[ps->top - 1];


int Stacksize(Stack* ps)

	assert(ps);

	return ps->top;


bool Stackempty(Stack* ps)

	assert(ps);

	return ps->top == 0;


void Stackdestroy(Stack* ps)

	assert(ps);

	free(ps->arr);
	ps->arr = NULL;
	ps->top = 0;
	ps->capacity = 0;

test.c

#include "Stack.h"

void testStack()

	Stack st;

	Stackinit(&st);

	int i = 0;
	for (i = 1; i <= 8; i++)
	
		Stackpush(&st, i);
	
	printf("%d\\n ", Stacksize(&st));
	/*while (!Stackempty(&st))
	
		printf("%d  ", Stacktop(&st));
		Stackpop(&st);
	*/
	printf("\\n");
	Stackdestroy(&st);


int main()

	testStack();

	return 0;


🐲👻关于栈的讲解就到这里了,若有错误或是建议欢迎小伙伴们指出。🐯🤖

🥰🤩希望小伙伴们可以多多支持博主哦。😍😃

😁😄谢谢你的阅读。😼😸

 

数据结构与算法堆的实现(附源码)

 

目录

一.堆的概念及结构

二.接口实现

A.初始化  Heapinit   销毁 Heapdestroy

B.插入 Heappush 向上调整  AdjustUp

1.Heappush

2.AdjustUp

C.删除 Heappop  向下调整  AdjustDown

D.堆的判空  Heapempty  堆顶数据  Heaptop  堆的大小  Heapsize

三.源码

Heap.h

Heap.c

test.c


一.堆的概念及结构

1.概念

     如果有一个关键码的集合K = , , ,…, ,把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足: <= 且 <= ( >= 且 >= ) i = 0,1,2…,则称为小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。
2.堆的性质:
    A.堆中某个节点的值总是不大于或不小于其父节点的值
    B.堆总是一棵完全二叉树

其实堆是一种二叉树,通常我们都是用数据表实现,也就是说堆的底层是数组,数组中的小标表示二叉树的节点,所以在实现堆之前,我们有必要了解完全二叉树中节点之间的关系

1.理解父节点 parent 和子节点 child;

2.了解父节点与子节点之间的关系:

   A.parent=(child-1)/2;

   B.左孩子child=2*parent+1;

   C.右孩子child=2*parent+2。

二.接口实现

A.初始化  Heapinit   销毁 Heapdestroy

这里的初始化和销毁都很简单,相信这对学到堆的人并不是什么难事,和顺序表的操作是一样的,如果实在不理解的话,请看 ->  顺序表

B.插入 Heappush 向上调整  AdjustUp

1.Heappush

插入数据很简单,直接对数组赋值,然后 size 再加加就行了,但是在插入完数据后,我们得保证它是堆,所以这就需要用到向上调整这个函数。

2.AdjustUp

假设我们建的是大堆,我们将新插入的节点与它的父节点比较:

1.如果比它的父节点大,则与其交换,所以交换后的父节点就成为了子节点,再与其父节点比较,以此类推

2.如果child<=0 则结束循环

void Swap(HPdatatype* p1, HPdatatype* p2)  //交换函数

	HPdatatype tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;


void AdjustUp(HPdatatype* arr, int child)   //向上调整

	assert(arr);

	int parent = (child - 1) / 2;

	while (child > 0)
	
		if (arr[child] > arr[parent])
		
			Swap(&arr[child], &arr[parent]);
			child = parent;
			parent = (child - 1) / 2;
		
		else
			break;
	


void Heappush(Heap* php, HPdatatype x)

	assert(php);

	if (php->size == php->capacity)
	
		HPdatatype* tmp = (HPdatatype*)realloc(php->arr, 2 * sizeof(HPdatatype) * php->capacity);
		if (tmp == NULL)
		
			perror("realloc fail");
			exit(-1);
		

		php->arr = tmp;
		php->capacity *= 2;
	

	php->arr[php->size] = x;
	php->size++;

	AdjustUp(php->arr, php->size - 1);  //注意这里要传size-1,因为size表示的是下一个位置

C.删除 Heappop  向下调整  AdjustDown

1.删除的话,我们是要删除堆顶的数据,因为删除堆尾的数据并没有什么实际意义,删除就是让size--,但是堆顶数据的下标是0,所以在删除前应先交换堆顶和堆尾的数据

2.删除完后,还要保持它还是个堆,不能把后面的顺序搞乱了,要想达到这个目的,就需要使用到向下调整这个函数;

3.假设是大堆,向下调整是父节点与其较大的子节点比较,如果较大的那个子节点大于父节点,则二者交换,然后较大的子节点成为了新的父节点,当子节点的下标大于或是等于节点总数,也就是size时,就结束循环。

 

D.堆的判空  Heapempty  堆顶数据  Heaptop  堆的大小  Heapsize

这些接口的实现都非常简单,博主就不在这里讲述了,可以参考后面的源码。


三.源码

Heap.h

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
#include <time.h>

#define MAX_MIN <   //通过改变这里的符号,可以决定是建大堆还是小堆

typedef int HPdatatype;

typedef struct Heap

	HPdatatype* arr;
	int size;
	int capacity;
Heap;

void Heapinit(Heap* php);

void Swap(HPdatatype* p1, HPdatatype* p2);

void AdjustUp(HPdatatype* arr, int child);  //向上调整

void Heappush(Heap* php, HPdatatype x);

void AdjustDown(HPdatatype* arr, int parent, int n);  //向下调整

void Heappop(Heap* php);

HPdatatype Heaptop(Heap* php);

int Heapsize(Heap* php);

bool Heapempty(Heap* php);

void Heapdestroy(Heap* php);

Heap.c

#include "Heap.h"


void Heapinit(Heap* php)

	assert(php);

	php->arr = (HPdatatype*)malloc(sizeof(HPdatatype) * 4);
	if (php->arr == NULL)
	
		perror("malloc fail");
		exit(-1);
	
	php->size = 0;
	php->capacity = 4;


void Swap(HPdatatype* p1, HPdatatype* p2)

	HPdatatype tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;


///С

void AdjustUp(HPdatatype* arr, int child)

	assert(arr);

	int parent = (child - 1) / 2;

	while (child > 0)
	
		if (arr[child] MAX_MIN arr[parent])
		
			Swap(&arr[child], &arr[parent]);
			child = parent;
			parent = (child - 1) / 2;
		
		else
			break;
	


void Heappush(Heap* php, HPdatatype x)

	assert(php);

	if (php->size == php->capacity)   //插入前,判断数组是否已满
	
		HPdatatype* tmp = (HPdatatype*)realloc(php->arr, 2 * sizeof(HPdatatype) * php->capacity);
		if (tmp == NULL)
		
			perror("realloc fail");
			exit(-1);
		

		php->arr = tmp;
		php->capacity *= 2;
	

	php->arr[php->size] = x;
	php->size++;

	AdjustUp(php->arr, php->size - 1);  //这里要传size-1


void AdjustDown(HPdatatype* arr, int parent, int n)

	assert(arr);

	int child = 2 * parent + 1;

	while (child < n)
	
        //判断较大(较小)的子节点
		if ((child + 1) < n && arr[child + 1] MAX_MIN arr[child])  
		
			child++;
		

		if (arr[child] MAX_MIN arr[parent])
		
			Swap(&arr[child], &arr[parent]);
			parent = child;
			child = 2 * parent + 1;
		
		else
			break;
	


void Heappop(Heap* php)

	assert(php);
	assert(php->size);
	Swap(&php->arr[0], &php->arr[php->size - 1]);
	php->size--;

	AdjustDown(php->arr, 0, php->size);


HPdatatype Heaptop(Heap* php)

	assert(php);
	assert(php->size);   //为空时不能取数据

	return php->arr[0];


int Heapsize(Heap* php)

	assert(php);

	return php->size;


bool Heapempty(Heap* php)

	assert(php);

	return php->size == 0;  //size==0即为空


void Heapdestroy(Heap* php)

	assert(php);
	free(php->arr);
	php->arr = NULL;
	php->size = 0;
	php->capacity = 0;

test.c

#include "Heap.h"


void testHeap()

	Heap hp;
	Heapinit(&hp);

	int i = 0, n = 10;
	int x = 0;
	while (n)
	
		x = rand() % 100 + 1;

		Heappush(&hp, x);
		n--;
	
	while (!Heapempty(&hp))
	
		printf("%d  ", Heaptop(&hp));
		Heappop(&hp);
	

	printf("\\n");
	Heapdestroy(&hp);


int main()

	srand((unsigned int)time(NULL));
	testHeap();

	return 0;

🐲👻这循环队列的讲解就到这里了,若有错误或是建议欢迎小伙伴们指出。🐯🤖

🥰🤩希望小伙伴们可以多多支持博主哦。😍😃

😁😄谢谢你的阅读。😼😸

 

以上是关于数据结构与算法栈的实现(附源码)的主要内容,如果未能解决你的问题,请参考以下文章

数据结构算法C语言实现--- 3.2栈的应用举例:迷宫求解与表达式求值

数据结构与算法栈与队列C语言版

Python数据结构与算法(3.1)——栈

五种编程语言解释数据结构与算法—链式栈

java数据结构与算法之栈(Stack)设计与实现

『数据结构与算法』栈:原理与实现