数据结构——树

本文介绍了二叉树的四种遍历方式:先序、中序、后序和层次遍历,以及非递归实现的中序遍历。此外,还详细讲解了哈夫曼树的构造、初始化、编码过程,以及如何通过哈夫曼编码生成最优前缀编码。内容涵盖了数据结构与算法中的基本概念和实现细节。
摘要由CSDN通过智能技术生成

1.二叉树

#pragma once
#include<iostream>
using namespace std;
#include"顺序栈.h"
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define INFEASIBLE -1
#define MAXSIZE 100
typedef int Status;
typedef char ElemType;

//二叉树的定义
typedef struct BiNode
{
	ElemType data;
	struct BiNode* lchild, * rchild;
}* BiTree;
//二叉树先序遍历
Status PreOrderTraver(BiTree& T)
{
	if (T == nullptr)
	{
		return OK;
	}
	visit(T);
	PreOrderTraver(T->lchild);
	PreOrderTraver(T->rchild);
}
//中序遍历
Status InOrderTraver(BiTree& T)
{
	if (T == nullptr)
	{
		return OK;
	}
	InOrderTraver(T->lchild);
	visit(T);
	InOrderTraver(T->rchild);
}
//后序遍历
Status InOrderTraver(BiTree& T)
{
	if (T == nullptr)
	{
		return OK;
	}
	InOrderTraver(T->lchild);
	InOrderTraver(T->rchild);
	visit(T);
}
//二叉树的中序遍历——非递归算法
void LDR(BiTree& T)
{
	//第一步:创建一个栈,用于保存二叉树的结点
	SqStack S;
	InitSqStack(S);
	BiTree p = T;
	while (p || !IsEmpty(S))
	{
		if (p)
		{
			Push(S, p);
			p = p->lchild;
		}
		else
		{
			Pop(S, q);
			visit(p);
			p = q->rchild;
		}
	}
}
//二叉树的层次遍历
void LevelOrder(BiTree& S)
{
	/*
	算法设计思路:
	1.将根结点入队
	2.队列不为空时循环,从队列中出列一个元素,访问它,并作以下步骤:
		2.1 如果该元素的左孩子不为空,让该元素的左孩子入队
		2.2 如果该元素的右孩子不为空,让该元素的右孩子入队
	*/
	SqQueue Q;
	InitSqQueue(Q);

	BiTree p;
	PushQueue(Q, S);
	while (!QueueEmpty(Q))
	{
		//将根结点出队
		DeQueue(Q, p);
		//访问根结点
		cout << p->data << endl;
		//if判断,是否能将根结点的左右孩子进队
		if (p->lchild != nullptr)
		{
			PushQueue(Q, p->lchild);
		}
		if (p->rchild != nullptr)
		{
			PushQueue(Q, p->rchild);
		}
	}
}

//二叉树的建立
bool CreatBiTree(BiTree& T)
{
	ElemType input;
	cin >> input;
	if (input == -1)//建立空结点的标志为 -1(这个自己设定一个就好)
		return false;
	T = new BiNode;
	//D
	T->data = input;
	//L
	CreatBiTree(T->lchild);
	//R
	CreatBiTree(T->rchild);
	return true;
}
//二叉树的复制
bool CopyBiTree(const BiTree& T, BiTree& NewT)
{
	if (T == nullptr)
	{
		return false;
	}
	NewT = new BiNode;
	//D
	NewT->data = T->data;
	//L
	CopyBiTree(T->lchild, NewT->lchild);
	//R
	CopyBiTree(T->rchild, NewT->rchild);
	return true;
}
//二叉树的深度
int Depth(BiTree& T)
{
	if (T == nullptr)
	{
		return 0;
	}
	int m = Depth(T->lchild);
	int n = Depth(T->rchild);
	if (m > n)
		return m + 1;
	else
		return n + 1;
}
//二叉树的结点数
int Depth(BiTree& T)
{
	if (T == nullptr)
	{
		return 0;
	}
	int m = Depth(T->lchild);
	int n = Depth(T->rchild);
	if (m > n)
		return m + 1;
	else
		return n + 1;
}
//求二叉树的叶子节点数
int Count0Node(BiTree& T)
{
	//③:递归函数将上一个结点剖分成左右子树,如果结点的孩子为空,那么返回0
	//这里不会出现结点的两个孩子都是空的,因为上一个结点执行这个递归函数的时候就已经判断了这种情况
	//这个语句只是为了以下两种情况而存在的:
	//1. 空树
	//2. 某个分支结点只有一个孩子
	if (T == nullptr)
	{
		return 0;
	}
	//①:其实呢,我们还是可以把这个问题拆分成左子树和右子树的统计问题
	if (T->lchild == nullptr && T->rchild == nullptr)
	{
		//以T为根结点的这棵树,左右孩子都没有,那他就是叶子结点
		return 1;
	}
	//②:如果不是这个情况,就说明这个根结点至少有一个孩子,还要继续剖分这个结点
	return Count0Node(T->lchild) + Count0Node(T->rchild);
}

2.哈夫曼树:


//哈夫曼树的定义
typedef struct HNode
{
	int weight;                 //权重
	int parent, lchild, rchild; //每个结点的双亲、左右孩子的数组下标
} *HuffmanTree;
//哈夫曼树初始化
void InitHTree(HuffmanTree& H, const int n)
{
	//哈夫曼树的存储结构为顺序存储
	//由哈夫曼树的构造过程得知,n个权重结点构造出的哈夫曼树具有2*n-1个结点
	//通常哈夫曼树的顺序存储结构下标从1开始计数,因此,如果我们使用数组实现的话
	//那么数组的长度应该是2*n
	H = new HNode[2 * n];
	for (int i = 1; i < 2 * n; ++i)
	{
		H[i].parent = H[i].lchild = H[i].rchild = 0;//右结合律
	}
	int input;
	for (int i = 1; i <= n; ++i)
	{
		cin >> input;
		H[i].weight = input;
	}
}
//哈夫曼树构造
void CreatHuffman(HuffmanTree& H, const int length)
{
	//第一步:对哈夫曼树进行初始化
	InitHTree(H, length);
	//第二步:找出当前森林中最小的两棵树,创建新树,并让原来的两个树作为新树的孩子
	for (int i = length + 1; i < 2 * length; ++i)
	{
		int i1 = 0, i2 = 0;
		Select(H, i - 1, i1, i2);//重点是这个Select算法
		H[i].weight = H[i1].weight + H[i2].weight;//
		H[i1].parent = H[i2].parent = i;
		H[i].lchild = i1;
		H[i].rchild = i2;
	}
}
void Select(HuffmanTree& H, const int n, int& i1, int& i2)
{
	vector<int> vec;
	for (int i = 1; i <= n; ++i)
	{
		if (H[i].parent == 0)
		{
			vec.push_back(i);
		}
	}
	//找出最小的一个
	auto flag1 = vec.begin();
	for (auto it = vec.begin() + 1; it != vec.end(); ++it)
	{
		if (H[*it].weight < H[*flag1].weight)
		{
			flag1 = it;
		}
	}
	i1 = *flag1; //最小的元素下标
	vec.erase(flag1);
	auto flag2 = vec.begin();
	for (auto it = vec.begin() + 1; it != vec.end(); ++it)
	{
		if (H[*it].weight < H[*flag2].weight)
		{
			flag2 = it;
		}
	}
	i2 = *flag2; //第二小的元素的下标
}
//哈夫曼编码
void HuffmanCode(HuffmanTree& H, const int n)
{
	//第一步:调用函数创建一个顺序存储结构的哈夫曼树,同上的函数一样
	CreatHuffman(H, n);
	//第二步:遍历哈夫曼树中每一个叶子结点,也即哈夫曼数组中的前n个元素
	for (int i = 1; i <= n; ++i)
	{
		int chd = i;
		int par = H[chd].parent;
		//自下而上得到哈夫曼编码,用栈来保存再合适不过了
		SqStack S;
		InitStack(S);
		while (par != 0)
		{
			H[par].lchild == chd ? /*0进栈*/ Push(S, 0) : /*1进栈*/ Push(S, 1);
			chd = par;
			par = H[chd].parent;
		}
		//出栈//黑框中打印编码
		while (!IsEmpty(S))
		{
			int out;
			Pop(S, out);
			cout << out;
		}
		cout << endl;
	}
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值