数据结构--树

116 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 21 天,点击查看活动详情

一、顺序存储与链式存储

队列---顺序存储

  • 利用写好的动态数组实现 顺序存储的队列数据结构

  • 对外提供的接口

  • 初始化队列

  • 入队

  • 出队

  • 返回队头

  • 返回队尾

  • 返回队列大小

  • 销毁队列

  • 判断队列是否为空

示例程序

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

#include "seqQueue.h"

//测试队列
struct Person
{
	char name[64];
	int age;
};

void test01()
{
	//初始化队列
	seqQueue queue = init_SeqQueue();
	//准备数据
	struct Person p1 = { "aaa", 10 };
	struct Person p2 = { "bbb", 20 };
	struct Person p3 = { "ccc", 30 };
	struct Person p4 = { "ddd", 40 };
	struct Person p5 = { "eee", 50 };
	//入队
	push_SeqQueue(queue, &p1);
	push_SeqQueue(queue, &p2);
	push_SeqQueue(queue, &p3);
	push_SeqQueue(queue, &p4);
	push_SeqQueue(queue, &p5);

	while ( size_SeqQueue(queue)>0 )
	{
		//获取队头元素
		struct Person * pFront = front_SeqQueue(queue);
		printf("队头元素--- 姓名: %s  年龄: %d\n", pFront->name, pFront->age);

		//获取队尾
		struct Person * pBack = back_SeqQueue(queue);
		printf("队尾元素--- 姓名: %s  年龄: %d\n", pBack->name, pBack->age);

		//出队
		pop_SeqQueue(queue);
	}

	printf("队伍大小为: %d\n", size_SeqQueue(queue));


	//销毁
	destroy_SeqQueue(queue);


}

int main(){

	test01();

	system("pause");
	return EXIT_SUCCESS;
}

队列---链式存储

  • 和顺序存储对外接口一致

  • 利用链表方式实现

  • 实现出一种 符合 先进先出的数据结构

队列链式存储解析图

队列的链式存储解析图.png

二、树的基本概念

  • 根节点 没有前驱的节点

  • 叶子节点 没有后继节点

  • 双亲 前驱节点

  • 孩子 后继节点

  • 节点的度 该节点的直接后继的数量

  • 树的度 节点的度中 最大的值

  • 树的高度 树的层数

三、二叉树性质

  1. 性质1: 在二叉树的第i层上至多有2i-1个结点(i>0)

  2. 性质2: 深度为k的二叉树至多有2k-1个结点(k>0)

  3. 性质3: 对于任何一棵二叉树,若度为2的结点数有n2个,则叶子数(n0)必定为n2+1 (即n0=n2+1)

    • 满二叉树 结点数量为 2k-1

    • 完全二叉树 除了最后一层结点,上面是一棵满二叉树,最后一层的节点尽量往左靠

  4. 性质4: 具有n个结点的完全二叉树的深度必为|log2n|+1

  5. 性质5: 对完全二叉树,若从上至下、从左至右编号,则编号为i 的结点,其左孩子编号必为2i,其右孩子编号必为2i+1;其双亲的编号必为i/2(i=1 时为根,除外)

四、二叉树的递归遍历

  • 利用树递归特性可以将二叉树进行递归遍历

  • 先序遍历 先根 再左 再右

  • 中序遍历 先左 再根 再右

  • 后序遍历 先左 再右 再根

  • 利用代码实现二叉树递归遍历

二叉树的递归遍历解析图

二叉树的递归遍历解析图.png

五、二叉树编程

  • 利用递归特性 求出二叉树中的叶子的数量

  • 求出二叉树的高度

  • 利用递归特性 拷贝出二叉树

六、二叉树的非递归遍历

  1. 利用栈 实现

  2. 首先将每个节点都设置一个标志,默认标志为假,根据节点的的状态进行如下流程

    • 将根节点压入栈中

    • 进入循环:只要栈中元素个数大于0 ,进行循环操作。

      1. 弹出栈顶元素

      2. 如果这个栈顶元素标志为真,输出这个元素并且执行下一次循环

      3. 如果栈顶元素标志为假,将节点的标志设为真

      4. 将该节点的右子树、左子树、根压入到栈中

      5. 执行下一次循环

二叉树的非递归遍历解析图

二叉树的非递归遍历解析图.png

七、插入排序

  • 外层大循环 从下标为1开始

  • 内存小循环 ,满足一定条件后,数据后移

  • 将数据插入到相应的位置上 j + 1位置

插入排序解析图

插入.png

示例程序

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

//从小到大
void insertSort(int arr[] , int len)
{
	for (int i = 1; i < len;i++)
	{
		if (arr[i] < arr[i-1])
		{
			int temp = arr[i]; //利用temp保存当前 i号位置的数据值
			int j = i - 1;
			for (; j >= 0 && temp < arr[j];j--)
			{
				//数据进行后移
				arr[j + 1] = arr[j];
			}
			//将j+1 的位置数据 赋值为 temp
			arr[j + 1] = temp;
		}

	}
}

void printArray(int arr[], int len)
{
	for (int i = 0; i < len;i++)
	{
		printf("%d\n", arr[i]);
	}
}

void test01()
{
	int arr[] = { 5, 9, 6, 1, 3, 7 };
	int len = sizeof(arr) / sizeof(int);
	insertSort(arr, len);

	
	//打印数组
	printArray(arr,len);
}


int main(){
	test01();


	system("pause");
	return EXIT_SUCCESS;
}