嵌入式学习DAY22 --- 链式栈,队列,二叉树的存储、递归遍历、层次遍历(数据结构)

这篇博客详细介绍了嵌入式编程中链式栈、顺序队列和链式队列的C语言实现,包括创建、入栈/入队、出栈/出队、销毁等操作,并提供了完整的源代码。同时,博主探讨了线性表的特点和顺序表与链表的区别,以及二叉树的基本概念、性质和遍历方法,如先序、中序、后序及层次遍历。通过示例代码展示了二叉树的层次遍历实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

嵌入式入门学习笔记,遇到的问题以及心得体会!
DAY22

笔记:

一.链式栈的实现:

1.stack.h ----------------------------------------------------- 如下

#ifndef _STACK_H_
#define _STACK_H_

typedef int data_t;

typedef struct StackNode
{
	data_t data;
	struct StackNode *pNext;
}StackNode;

typedef struct Stack
{
	StackNode *pHead;
	int count;
}Stack;

enum STACK_OP
{
	STACK_ERROR = -1,
	STACK_EMPTY,
	STACK_OK
};
//创建
Stack *createStack();
//入栈
int pushStack(Stack *pStack,data_t tData);
//出栈
int popStack(Stack *pStack,data_t *pData);
//销毁
void destroyStack(Stack **ppStack);
//判断是否为空
int isEmpty(Stack *pStack);
#endif

2.stack.c ----------------------------------------------------- 如下

#include <stdio.h>
#include "stack.h"
#include <stdlib.h>
#include <string.h>


//创建
Stack *createStack()
{
	Stack *pStack = (Stack *)malloc(sizeof(Stack));
	if(NULL == pStack)
	{
	
		return NULL;
	}
	pStack->pHead = NULL;
	pStack->count = 0;
	return pStack;
}
//入栈
int pushStack(Stack *pStack,data_t tData)
{
	if(NULL == pStack)
	{
		return STACK_ERROR;
	}
	StackNode *pNode = (StackNode*)malloc(sizeof(StackNode));
	memset(pNode,0,sizeof(StackNode));
	pNode->data = tData;

	if(NULL == pStack->pHead)
	{
		pStack->pHead = pNode;
		pStack->count++;
		return STACK_OK;
	}
	pNode->pNext = pStack->pHead;
	pStack->pHead = pNode;
	pStack->count++;
	return STACK_OK;
}
//出栈
int popStack(Stack *pStack,data_t *pData)
{
	if(NULL == pStack || NULL == pStack->pHead || NULL == pData)
	{
		return STACK_ERROR;
	}
	*pData = pStack->pHead->data;
	if(1 == pStack->count)
	{
		free(pStack->pHead);
		pStack->pHead = NULL;
		pStack->count--;
		return STACK_OK;
	}
	StackNode *pTemp = pStack->pHead;
	pStack->pHead = pStack->pHead->pNext;
	free(pTemp);
	pTemp = NULL;
	pStack->count--;

}
//销毁
void destroyStack(Stack **ppStack)
{
	if(NULL == ppStack || NULL ==*ppStack || (*ppStack)->pHead)
	{
		return;
	}
	StackNode *pTemp = NULL;
	while((*ppStack)->pHead != NULL)
	{
		pTemp = (*ppStack)->pHead;
		(*ppStack)->pHead = (*ppStack)->pHead->pNext;
		free(pTemp);
	}
	pTemp = NULL;
	free(*ppStack);
	*ppStack = NULL;

}
//判断是否为空栈
int isEmpty(Stack *pStack)
{
	if(NULL == pStack)
	{
		return STACK_ERROR;
	}
	if(NULL == pStack->pHead)
	{
		return STACK_EMPTY;
	}
	return STACK_OK;
}


3.main.c ----------------------------------------------------- 如下

#include <stdio.h>
#include "stack.h"
#include <string.h>
#include <stdlib.h>

int main(int argc, const char *argv[])
{
	Stack *pStack = createStack();
	if(NULL == pStack)
	{
		return -1;
	}
	data_t data;
	int i;
	for(i=0;i<5;i++)
	{
		pushStack(pStack,i);
	}
	while(STACK_EMPTY != isEmpty(pStack))
	{
		popStack(pStack,&data);
		printf("%d ",data);
	}
	printf("\n");
	destroyStack(&pStack);
	return 0;
}

二.顺序队列的实现

1.seqqueue.h ----------------------------------------------------- 如下

#ifndef _QUEUE_H_
#define _QUEUE_H_
#define SIZE 5
typedef int data_t;

typedef struct Queue
{
	data_t data[SIZE];
	int iFront;
	int iRear;
	int count;
}Queue;

enum QUEUE_OP
{
	QUEUE_ERR = -1,
	QUEUE_OK,
	QUEUE_EMPTY,
	QUEUE_FULL
};

Queue *CreateQueue();
int enQueue(Queue *pQueue, data_t tData);
int deQueue(Queue *pQueue, data_t *pData);
int isEmpty(Queue *pQueue);
int isFull(Queue *pQueue);
void destroyQueue(Queue **ppQueue);

#endif

2.seqqueue.c ----------------------------------------------------- 如下

#include<stdio.h>
#include "seqqueue.h"
#include <stdlib.h>
#include <string.h>

Queue *CreateQueue()
{
	Queue *pQueue = (Queue *)malloc(sizeof(Queue));
	if(NULL == pQueue)
	{
		return NULL;
	}
	memset(pQueue, 0, sizeof(Queue));
	return pQueue;
}
int enQueue(Queue *pQueue, data_t tData)
{
	if(NULL == pQueue)
	{
		return QUEUE_ERR;
	}

    pQueue->data[pQueue->iRear] = tData;
	pQueue->iRear++;
	pQueue->count++;
	return QUEUE_OK;
}
int deQueue(Queue *pQueue, data_t *pData)
{
	if(NULL == pQueue || NULL == pData)
	{
		return QUEUE_ERR;
	}
	//先将原来的值保存起来
	//再移动队头
	*pData = pQueue->data[pQueue->iFront];
	pQueue->iFront++;
	pQueue->count--;
	return QUEUE_OK;
}
int isEmpty(Queue *pQueue)
{
	if(NULL == pQueue)
	{
		return QUEUE_ERR;
	}
	if(0 == pQueue->count)
	{
		return QUEUE_EMPTY;
	}
	return QUEUE_OK;
}
int isFull(Queue *pQueue)
{
	if(NULL == pQueue)
	{
		return QUEUE_ERR;
	}
	if(SIZE == pQueue->count)
	{
		return QUEUE_FULL;
	}
	return QUEUE_OK;
}

void destroyQueue(Queue **ppQueue)
{
	if(NULL == ppQueue || NULL == *ppQueue)
	{
		return;
	}
	free(*ppQueue);
	*ppQueue = NULL;
}

3.main.c ----------------------------------------------------- 如下

#include<stdio.h>
#include "seqqueue.h"

int main()
{
	Queue *pQueue = CreateQueue();

	data_t data;
	while(QUEUE_FULL != isFull(pQueue))
	{
		scanf("%d", &data);
		enQueue(pQueue, data);
	}


	printf("出队的结果为:");
	while(QUEUE_EMPTY != isEmpty(pQueue))
	{
		deQueue(pQueue, &data);
		printf("%d ", data);
	}
	printf("\n");
	destroyQueue(&pQueue);
	return 0;
}

三.链式队列的实现

在这里插入图片描述
定义结构体:

Struct QueueNode
{
Data_t data;
Struct QueueNode *pNext;
};

Struct Queue
{
Struct QueueNode *pHead;
Struct QueueNode *pTail;
Int count;
};

代码实现:

1.queue.h ----------------------------------------------------- 如下

#ifndef _QUEUE_H_
#define _QUEUE_H_

typedef int data_t;

typedef struct QueueNode
{
	data_t data;
	struct QueueNode *pNext;
}QueueNode;


typedef struct Queue
{
	QueueNode *pHead;
	QueueNode *pTail;
	int count;
}Queue;

enum QUEUE_OP
{
	QUEUE_ERR = -1,
	QUEUE_OK,
	QUEUE_EMPTY
};

Queue *createQueue();
int enQueue(Queue *pQueue, data_t tData);
int deQueue(Queue *pQueue, data_t *pData);
int isEmpty(Queue *pQueue);
void destroyQueue(Queue **ppQueue);

#endif

2.queue.c ----------------------------------------------------- 如下

#include<stdio.h>
#include "queue.h"
#include <stdlib.h>
#include <string.h>

Queue *createQueue()
{
	Queue *pQueue = (Queue *)malloc(sizeof(Queue));
	if(NULL == pQueue)
	{
		return NULL;
	}
	memset(pQueue, 0, sizeof(Queue));
	return pQueue;
}

int enQueue(Queue *pQueue, data_t tData)
{
	if(NULL == pQueue)
	{
		return QUEUE_ERR;
	}

	QueueNode *pNode = (QueueNode *)malloc(sizeof(QueueNode));
	if(NULL == pNode)
	{
		return QUEUE_ERR;
	}
	memset(pNode, 0, sizeof(QueueNode));
	pNode->data = tData;
	//当为空队列时,需要单独处理
	if(0 == pQueue->count)
	{
		pQueue->pHead = pNode;
		pQueue->pTail = pNode;
		pQueue->count++;
		return QUEUE_OK;
	}
	pQueue->pTail->pNext = pNode;
	//更新pTail
    pQueue->pTail = pNode;
	pQueue->count++;
	return QUEUE_OK;
}

int deQueue(Queue *pQueue, data_t *pData)
{
	if(NULL == pQueue)
	{
		return QUEUE_ERR;
	}
	QueueNode *pDel = pQueue->pHead;
	*pData = pDel->data;

	pQueue->pHead = pDel->pNext;
    free(pDel);
	pDel = NULL;
	pQueue->count--;
	return QUEUE_OK;
}
int isEmpty(Queue *pQueue)
{
	if(NULL == pQueue)
	{
		return QUEUE_ERR;
	}
	if(0 == pQueue->count)
	{
		return QUEUE_EMPTY;
	}
	return QUEUE_OK;
}
void destroyQueue(Queue **ppQueue)
{
	if(NULL == ppQueue || NULL == *ppQueue || NULL == (*ppQueue)->pHead)
	{
		return;
	}

	QueueNode *pDel = (*ppQueue)->pHead;
	while(pDel != NULL)
	{
		(*ppQueue)->pHead = pDel->pNext;
		free(pDel);
		pDel = (*ppQueue)->pHead;
	}

	free(*ppQueue);
	*ppQueue = NULL;
}

3.main.c ----------------------------------------------------- 如下

#include<stdio.h>
#include "queue.h"


int main()
{
	Queue *pQueue = createQueue();
	data_t data;

	while(1)
	{
		printf("请入队:");
		scanf("%d", &data);
		if(0 == data)
		{
			break;
		}
		enQueue(pQueue, data);
	}

	printf("出队结果为:");
	while(QUEUE_EMPTY != isEmpty(pQueue))
	{
		deQueue(pQueue, &data);
		printf("%d ", data);
	}
	printf("\n");


	destroyQueue(&pQueue);
	return 0;
}

总结:

1、线性表的特点
逻辑结构是一对一
存储结构有顺序存储和链式存储

2、我们学过了哪些线性表
顺序表 单链表 双向链表 栈 队列

3、栈和队列与顺序表和链表的联系和区别是什么
栈和队列属于顺序表和链表,栈和队列只是在他们的基础上进行了限制

4、顺序表和链表的区别
<1>顺序表是连续存储,链表是不连续的
<2>顺序表插入和删除需要数据搬移,效率低
<3>顺序表的查找效率非常高,只需要知道下标就可以找到
<4>链表的插入和删除效率比顺序表高,不需要数据搬移
<5>链表的查找效率低,需要遍历


一、树–二叉树

1、基本概念

(1)节点的度数:一个节点的子树的个数
(2)树的度数:一棵树的度数是指该树中节点的最大度数。
(3)叶子节点:度数为0的节点
(4)分支节点:度数不为0的节点
(5)根节点没有前驱节点,叶子节点没有后继节点

2、二叉树

(1)概念:一个节点最多只有两个节点,而且是严格区分左右的,哪怕只有只有一个子节点,也要区分左右,所以二叉树是有序树
(2)二叉树的性质
<1>二叉树第i(i≥1)层上的节点最多为2^(i-1)个。
<2>深度为k(k≥1)的二叉树最多有2^k-1个节点。
<3>在任意一棵二叉树中,树叶的数目比度数为2的节点的数目多一。
n0:度数为0的节点的个数
N1:度数为1的节点的个数
N2:度数为2的节点的个数
总节点数为各类节点之和:n = n0 + n1 + n2
总节点数为所有子节点数加一:n = n1 + 2*n2 + 1
故得:n0 = n2 + 1 ;
<4>满二叉树 :深度为k(k≥1)时有2^k-1个节点的二叉树。
<5>完全二叉树 :只有最下面两层有度数小于2的节点,且最下面一层的叶节点集中在最左边的若干位置上。
具有n个节点的完全二叉树的深度为
(log2n)+1或『log2(n+1)˥。
》k-1 <= log2n < k =>k <= log2n+1 < k+1=> log2n < k <= log2n+1 k是整数===》k = log2n+1

3、二叉树的存储

二叉树逻辑结构:一对多
存储结构:顺序存储和链式存储

链式存储中节点的描述方法:

Struct TreeNode
{
Data_t data;
Struct TreeNode *lChild;
Struct TreeNode *rChild;
};

4、二叉树的遍历

二叉树的遍历是指按某条搜索路径访问树中每个结点,使得每个结点均被访问一次,而且仅被访问一次。由于二叉树是一种非线性结构,每个结点都可能有两棵子树,因而需要寻找一种规律,以便使二叉树.上的结点能排列在一一个线性队列上,进而便于遍历。
由二叉树的递归定义可知,遍历一棵二叉树便要决定对根结点N、左子树L和右子树R的访问顺序。按照先遍历左子树再遍历有子树的原则,常见的遍历次序有先序(NLR)、 中序(LNR)和后序(LRN)三种遍历算法,其中“序”指的是根结点在何时被访问。

<递归遍历:>
(1)先根遍历(先序遍历):先访问树根,再访问左子树,最后访问右子树

void PreOrder (TreeNode *pRoot) 
{
	if (NULL == pRoot)
	{
		visit (pRoot) ; //访间根结点
		// printf("%c ", pRoot->data);
		
		PreOrder (pRoot->lchild) ;//递归遍历左子树

		PreOrder (pRoot->rchild) ;//递归遍历右子树
	}
}

中根遍历(中序遍历):先访问左子树,再访问树根,最后访问右子树

vold InOrder(TreeNode *pRoot)
 {
	if (NULL == pRoot) 
	{
		InOrder (pRoot->lchild); //递归遍历左子树
		visit(pRoot) ; //访问根结点
		// printf("%c ", pRoot->data);
		InOrder (pRoot->rchild) ;//递归遍历右子树
	}
}

后根遍历(后序遍历):先访问左子树,再访问右子树,最后访问树根

void PostOrder (TreeNode *pRoot) 
{
	If(NULL == pRoot) 
	{
		Postorder (pRoot->lchild); //递归遍历左子树
		Postorder (pRoot->rchild); //递归遍历右子树
		visit(pRoot);//访问根结点
		// printf("%c ", pRoot->data);
	}
}

<层次遍历:>

二叉树的层次遍历
二叉树的层次遍历
如图所示为二叉树的层次遍历,即按照箭头所指方向,按照1,2, 3,4的层次顺序,对二叉树中的各个结点进行访问。

要进行层次遍历,需要借助一个队列。先将二叉树根结点入队,然
后出队,访问出队结点,若它有左子树,则将左子树根结点入队:若它有右子树,则将右子树根结点入队。然后出队,访问出队结果…如此反复,直至队列为空。

二叉树的层次遍历算法如下:

void Levelorder (BiTree T) 
{
	InitQueue(Q) ;//初始化辅助队列
	BiTree Pi
	EnQueue(Q,T) ;//将根结点入队
	while ( IsEmpty(Q)) //队列不空则循环
	{
		DeQueue(O,p)//队头结点出队
		visit(p) ;//访问出队结点
		if (p->1child! =NULL)
		EnQueue (Q,p->lch11d); //左子树不空, 则左子树根结点入队
		if (p->rchild!=NULL)
		EnQueue (Q,p->rchild); //右子树不空, 则右子树根结点入队
	}
}

|
|
|
|

二.代码实现

1.tree.h----------------------------------------------------- 如下

#ifndef _TREE_H_
#define _TREE_H_

typedef char data_tree;

typedef struct TreeNode
{
	data_tree data;
	struct TreeNode *lChild, *rChild;
}TreeNode;



void createTree(TreeNode **ppRoot);
void preOrder(TreeNode *pRoot);
void inOrder(TreeNode *pRoot);
void postOrder(TreeNode *pRoot);
void destroyTree(TreeNode **ppRoot);
void levelOrder(TreeNode *pRoot);
#endif

2.tree.c----------------------------------------------------- 如下

#include<stdio.h>
#include "tree.h"
#include <stdlib.h>
#include <string.h>
#include "queue.h"

void createTree(TreeNode **ppRoot)
{
	data_tree data;
	printf("input:");
	scanf("%c", &data);
	getchar();
	if('#' == data)
	{
		//此时没有左子树或者右子树
		*ppRoot = NULL;
		return;
	}
	else
	{
		//先创建节点
		*ppRoot = (TreeNode *)malloc(sizeof(TreeNode));
		if(NULL == *ppRoot)
		{
			return;
		}
		(*ppRoot)->data = data;

		createTree(&((*ppRoot)->lChild));
		createTree(&((*ppRoot)->rChild));
	}
}
void preOrder(TreeNode *pRoot)
{
	if(NULL == pRoot)
	{
		return;
	}

    printf("%c ", pRoot->data);
	preOrder(pRoot->lChild);
	preOrder(pRoot->rChild);
}
void inOrder(TreeNode *pRoot)
{
	if(NULL == pRoot)
	{
		return;
	}
	inOrder(pRoot->lChild);
	printf("%c ", pRoot->data);
	inOrder(pRoot->rChild);
}
void postOrder(TreeNode *pRoot)
{
	if(NULL == pRoot)
	{
		return;
	}
	postOrder(pRoot->lChild);
	postOrder(pRoot->rChild);
	printf("%c ", pRoot->data);
}

void destroyTree(TreeNode **ppRoot)
{
	if(NULL == ppRoot || NULL == *ppRoot)
	{
		return;
	}
    destroyTree(&((*ppRoot)->lChild));
    destroyTree(&((*ppRoot)->rChild));
	free(*ppRoot);
	*ppRoot = NULL;
}

void levelOrder(TreeNode *pRoot)
{
	if(NULL == pRoot)
	{
		return;
	}

	//创建队列
	Queue *pQueue = createQueue();

	//根节点入队
	enQueue(pQueue, pRoot);

	//只要队列不为空,就出队
	//并且判断出队的节点有无左右子树
	//如果有就入队
	while(QUEUE_EMPTY != isEmpty(pQueue))
	{
		TreeNode *pNode;
		deQueue(pQueue, &pNode);
		printf("%c ", pNode->data);
		if(pNode->lChild != NULL)
		{
			enQueue(pQueue, pNode->lChild);
		}
		if(pNode->rChild != NULL)
		{
			enQueue(pQueue, pNode->rChild);
		}
	}
	printf("\n");
}

3.main.c----------------------------------------------------- 如下

#include<stdio.h>
#include "tree.h"


int main()
{
	TreeNode *pRoot = NULL;
	createTree(&pRoot);

	levelOrder(pRoot);

	destroyTree(&pRoot);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值