[c++] 树和二叉树

目录

内容描述

1. 普通二叉树和线索二叉树

2. 霍夫曼树

3. 输入输出示例

程序代码

TreeNode.h

MyTree.h

Huffman.h

TreeNode.cpp

MyTree.cpp

Huffman.cpp

main.cpp

测试结果


内容描述

1. 普通二叉树和线索二叉树

实现树的节点 TreeNode(支持线索二叉树)和树 MyTree(支持线索二叉树),采用二叉链表存储,完成以下功能:

  • 树节点的初始化和销毁
  • 树初始化,初始化一棵空树
  • 树初始化,根据二叉树的先序序列,生成二叉树的二叉链表存储,使用 @ 表示 NULL
  • 树的复制构造函数,复制参数中的树
  • 树销毁,支持普通二叉树与线索二叉树
  • 先序遍历二叉树并打印,仅支持普通二叉树,不考虑线索化,对节点的访问操作为打印该节点
  • 中序遍历二叉树并打印,支持普通二叉树与线索二叉树,对节点的访问操作为打印该节点
  • 后序遍历二叉树并打印,仅支持普通二叉树,不考虑线索化,对节点的访问操作为打印该节点
  • 定位二叉树中的节点,在树中找到值为v的节点则返回该节点,否则返回 NULL,支持普通二叉树与线索二叉树
  • 计算二叉树的叶子结点数,仅支持普通二叉树,不考虑线索化
  • 计算二叉树的深度,仅支持普通二叉树,不考虑线索化
  • 当前树是否是线索二叉树,是线索二叉树返回 true,否则 false
  • 为二叉树生成中序线索二叉树
  • 寻找中序线索二叉树中某节点的前驱节点,仅支持线索二叉树
  • 寻找中序线索二叉树中某节点的后继节点,仅支持线索二叉树

2. 霍夫曼树

实现霍夫曼树 HuffmanTree,输出对应的霍夫曼编码,具体完成以下功能:

  • 树初始化 HuffmanTree,根据输入创建一棵霍夫曼树,第一个参数为节点个数,第二个参数为节点数组,节点值为节点重要度,越大代表越重要,要求树构建时偏小的值放入左子树,偏大的值放入右子树
  • 树销毁
  • 输出霍夫曼编码,格式:节点值:编码,节点排序递减
  • 其他必要的函数

3. 输入输出示例

MyTree myTree("ABC@@DE@G@@F@@@");
myTree.preOrderTraverse();//ABCDEGF
cout << endl;
myTree.inOrderTraverse();//CBEGDFA
cout << endl;
myTree.postOrderTraverse();//CGEFDBA
cout << endl;
cout << myTree.countLeaf() << endl;//3
cout << myTree.countHeight() << endl;//5
 
MyTree myThreadedTree(myTree);
cout << myThreadedTree.isThreadedTree() << endl;//0
myThreadedTree.inOrderThreading();
cout << myThreadedTree.isThreadedTree() << endl;//1
myThreadedTree.inOrderTraverse();//CBEGDFA
cout << endl;
 
TreeNode n = myThreadedTree.locateNode('G');
myThreadedTree.preNode(n).printNode();//E
cout << endl;
myThreadedTree.nextNode(n).printNode();//D
 
cout << endl;	int v[] = {2,7,5,4};
HuffmanTree hTree(4, v);
hTree.printHuffmanCodes();
/*
7:0
5:10
4:111
2:110
*/

程序代码

TreeNode.h

#ifndef TREENODE_H
#define TREENODE_H

class TreeNode
{
public:
	char data;
	TreeNode* lchild, * rchild;
	bool ltag, rtag;

	TreeNode();
	~TreeNode();

	void printNode();
};

#endif

MyTree.h

#ifndef MyTree_H
#define MyTree_H
#include "TreeNode.h"

class MyTree {
private:
	TreeNode* treeNode;
	void preOrder(TreeNode*& tn, void(*pf)(TreeNode*& tn));
	void inOrder(TreeNode*& tn, void(*pf)(TreeNode*& tn));
	void postOrder(TreeNode*& tn, void(*pf)(TreeNode*& tn));
	void createTree(TreeNode*& tn, const char*& str);
	void createTree(TreeNode*& tn, const TreeNode* tn0);
	int Leaf(TreeNode*&& tn);
	int Height(TreeNode*&& tn);
	bool isThr(TreeNode*&& tn);
	void inOrderThr(TreeNode*& tn, TreeNode*&& pre);
	bool locate(char c, TreeNode* tn, TreeNode*& temp);

public:
	MyTree();
	MyTree(const char* str);
	MyTree(MyTree& mt);
	~MyTree();

	void preOrderTraverse();
	void inOrderTraverse();
	void postOrderTraverse();
	int countLeaf();
	int countHeight();
	bool isThreadedTree();
	void inOrderThreading();
	TreeNode locateNode(char c);
	TreeNode preNode(TreeNode tn);
	TreeNode nextNode(TreeNode tn);
};

#endif

Huffman.h

#ifndef HUFFMANTREE_H
#define HUFFMANTREE_H

class HuffmanTree {
private:
	typedef struct
	{
		int weight;   //结点的权值,为了方便直接用int
		int parent, lChild, rChild;  //左右孩子和双亲
	}HTNode,*HTree;
	HTree htree;
	int n;

	void select(int n, int& s1, int& s2);
public:
	HuffmanTree(int n, int w[]);
	~HuffmanTree();
	void printHuffmanCodes();
};

#endif

TreeNode.cpp

#include "TreeNode.h"
#include<bits/stdc++.h>

TreeNode::TreeNode()
{
	data = 0;
	lchild = nullptr;
	rchild = nullptr;
	ltag = 0;
	rtag = 0;
}

void TreeNode::printNode() {
	std::cout << data;
}

TreeNode::~TreeNode() {}

MyTree.cpp

#include "MyTree.h"
#include <bits/stdc++.h>

MyTree::MyTree() {
	treeNode = nullptr;
}

MyTree::MyTree(const char* str) {
	createTree(treeNode, str);
}

MyTree::MyTree(MyTree& mt) {
	createTree(treeNode, mt.treeNode);
	if (mt.isThreadedTree())
		inOrderThreading();
}

MyTree::~MyTree() {
	postOrder(treeNode, [](TreeNode*& tn)->void {delete tn; });
}

void MyTree::createTree(TreeNode*& tn, const char*& str)
{
	if (*str)
	{
		if (*str == '@')
		{
			tn = nullptr;
			return;
		}
		tn = new TreeNode;
		tn->data = *str;
		createTree(tn->lchild, ++str);
		createTree(tn->rchild, ++str);
	}
}

void MyTree::createTree(TreeNode*& tn, const TreeNode* tn0)
{
	if (tn0 == nullptr)
	{
		tn = nullptr;
		return;
	}
	tn = new TreeNode;
	tn->data = tn0->data;
	createTree(tn->lchild, tn0->lchild);
	createTree(tn->rchild, tn0->rchild);
}

void MyTree::preOrder(TreeNode*& tn, void(*pf)(TreeNode*& tn)) {
	if (tn == nullptr)return;
	(*pf)(tn);
	if (tn->ltag == 0)
		preOrder(tn->lchild, pf);
	if (tn->rtag == 0)
		preOrder(tn->rchild, pf);
}

void MyTree::inOrder(TreeNode*& tn, void(*pf)(TreeNode*& tn)) {
	if (tn == nullptr)return;
	if (tn->ltag == 0)
		inOrder(tn->lchild, pf);
	(*pf)(tn);
	if (tn->rtag == 0)
		inOrder(tn->rchild, pf);
}

void MyTree::postOrder(TreeNode*& tn, void(*pf)(TreeNode*& tn)) {
	if (tn == nullptr)return;
	if (tn->ltag == 0)
		postOrder(tn->lchild, pf);
	if (tn->rtag == 0)
		postOrder(tn->rchild, pf);
	(*pf)(tn);
}

void MyTree::preOrderTraverse() {
	preOrder(treeNode, [](TreeNode*& tn)->void {std::cout << tn->data; });
}

void MyTree::inOrderTraverse() {
	inOrder(treeNode, [](TreeNode*& tn)->void {std::cout << tn->data; });
}

void MyTree::postOrderTraverse() {
	postOrder(treeNode, [](TreeNode*& tn)->void {std::cout << tn->data; });
}

int MyTree::countLeaf() {
	return Leaf(std::move(treeNode));
}

int MyTree::Leaf(TreeNode*&& tn)
{
	if (tn == nullptr)return 0;
	else if ((tn->lchild == nullptr && tn->rchild == nullptr) || (tn->ltag == 1 && tn->rtag == 1))
		return 1;
	else if (tn->rchild == nullptr || tn->rtag == 1)return Leaf(std::move(tn->lchild));
	else if (tn->lchild == nullptr || tn->ltag == 1)return Leaf(std::move(tn->rchild));
	else return Leaf(std::move(tn->lchild)) + Leaf(std::move(tn->rchild));
}

int MyTree::countHeight() {
	return Height(std::move(treeNode));
}

int MyTree::Height(TreeNode*&& tn)
{
	if (tn == nullptr)return 0;
	else if ((tn->lchild == nullptr && tn->rchild == nullptr) || (tn->ltag == 1 && tn->rtag == 1))
		return 1;
	else if (tn->rchild == nullptr || tn->rtag == 1)return 1 + Height(std::move(tn->lchild));
	else if (tn->lchild == nullptr || tn->ltag == 1)return 1 + Height(std::move(tn->rchild));
	else return 1 + std::max(Height(std::move(tn->lchild)), Height(std::move(tn->rchild)));
}

bool MyTree::isThreadedTree() {
	return isThr(std::move(treeNode));
}

bool MyTree::isThr(TreeNode*&& tn) {
	if (tn == nullptr || (tn->lchild == nullptr && tn->ltag == 0))
		return false;
	else if (tn->ltag == 1)return true;
	else return isThr(std::move(tn->lchild));
}

void MyTree::inOrderThreading()
{
	inOrderThr(treeNode, nullptr);
}

void MyTree::inOrderThr(TreeNode*& tn, TreeNode*&& pre)
{
	if (tn == nullptr)return;
	inOrderThr(tn->lchild, std::move(pre));
	if (tn->lchild == nullptr)
	{
		tn->lchild = pre;
		tn->ltag = 1;
	}
	if (pre != nullptr && pre->rchild == nullptr)
	{
		pre->rchild = tn;
		pre->rtag = 1;
	}
	pre = tn;
	inOrderThr(tn->rchild, std::move(pre));
}

TreeNode MyTree::locateNode(char c)
{
	TreeNode* temp;
	locate(c, treeNode, temp);
	return *temp;
}

bool MyTree::locate(char c, TreeNode* tn, TreeNode*& temp)
{
	if (tn == nullptr)return false;
	else if (tn->data == c)
	{
		temp = tn;
		return true;
	}
	else if ((tn->lchild == nullptr && tn->rchild == nullptr) || (tn->ltag == 1 && tn->rtag == 1))
		return false;
	else if (tn->rchild == nullptr || tn->rtag == 1)return locate(c, tn->lchild, temp);
	else if (tn->lchild == nullptr || tn->ltag == 1)return locate(c, tn->rchild, temp);
	else return locate(c, tn->lchild, temp) || locate(c, tn->rchild, temp);
}

TreeNode MyTree::preNode(TreeNode tn) {
	if (tn.ltag == 1)return *tn.lchild;
	else {
		TreeNode* p = tn.lchild;
		while (p->rtag == 0)
		{
			p = p->rchild;
		}
		return *p;
	}
}

TreeNode MyTree::nextNode(TreeNode tn)
{
	if (tn.rtag == 1)
		return *tn.rchild;
	else {
		TreeNode* p = tn.rchild;
		while (p->ltag == 0)
		{
			p = p->lchild;
		}
		return *p;
	}
}

Huffman.cpp

#include "Huffman.h"
#include <bits/stdc++.h>

HuffmanTree::HuffmanTree(int n, int w[]) {
	int s1;
	int s2;
	this->n = n;
	int m = 2 * n - 1;
	htree = new HTNode[m];
	//1--n号空间存放叶子结点,初始化结点
	for (int i = 0; i < n; i++) {
		//其中叶子结点的权值是w[n]数组保存
		htree[i].weight = w[i];
		htree[i].lChild = -1;
		htree[i].rChild = -1;
		htree[i].parent = -1;
	}
	//对于其它的结点即非叶子结点
	for (int i = n; i < m; i++) {
		htree[i].weight = -1;
		htree[i].lChild = -1;
		htree[i].rChild = -1;
		htree[i].parent = -1;
	}

	//创建非叶子结点,构建哈夫曼树
	for (int i = n; i < m; i++) {
		//找到权值最小的两个结点,分别赋值给s1和s2
		select(i, s1, s2);
		htree[s1].parent = i;
		htree[s2].parent = i;
		htree[i].lChild = s1;
		htree[i].rChild = s2;
		htree[i].weight = htree[s1].weight + htree[s2].weight;
	}
}

HuffmanTree::~HuffmanTree() {
	delete[]htree;
}

void HuffmanTree::select(int num, int& s1, int& s2) {
	int min;
	//遍历全部的结点,找出一个单结点
	for (int i = 0; i < num; i++) {
		if (htree[i].parent == -1) {
			min = i;
			break;
		}
	}
	//继续遍历全部结点,找出权值最小的单结点
	for (int i = 0; i < num; i++) {
		if (htree[i].parent == -1) {
			if (htree[i].weight < htree[min].weight) {
				min = i;
			}
		}
	}
	s1 = min;
	//进行和上面相同的操作,找到第二小的结点
	for (int i = 0; i < num; i++) {
		if (htree[i].parent == -1 && i != s1) {
			min = i;
			break;
		}
	}
	for (int i = 0; i < num; i++) {
		if (htree[i].parent == -1 && i != s1) {
			if (htree[i].weight < htree[min].weight) {
				min = i;
			}
		}
	}
	s2 = min;
}

void HuffmanTree::printHuffmanCodes() {
	//从n个叶子结点到根求哈弗曼编码
	std::string* huffmanCode = new std::string[n];	//创建一个储存编码的数组
	for (int i = 0; i < n; i++) {
		std::string code = "";
		//这里我们从叶子结点开始向上遍历
		for (int c = i, p = htree[i].parent; p != -1; c = p, p = htree[p].parent) {
			if (htree[p].lChild == c) {
				code = "0" + code;	//如果该结点是双亲结点的左孩子,则在编码前加‘0’
			}
			else {
				code = "1" + code;	//如果该结点是双亲结点的右孩子,则在编码前加‘1’
			}
		}
		huffmanCode[i] = code;
	}
	//节点排序递减输出编码
	int* weight = new int[n];
	for (int i = 0; i < n; ++i)
	{
		weight[i] = htree[i].weight;
	}
	//简单选择排序
	for (int i = 0; i < n; i++) {
		int max = i;
		for (int j = i + 1; j < n; ++j)
		{
			if (weight[j] > weight[max]) {
				max = j;
			}
		}
		std::cout << weight[max] << ": " << huffmanCode[max] << std::endl;
		int temp = weight[max];
		weight[max] = weight[i];
		weight[i] = temp;
		std::string code = huffmanCode[max];
		huffmanCode[max] = huffmanCode[i];
		huffmanCode[i] = code;
	}

	/*
	// 	for (int i = 0; i < n; i++) {
	// 		std::cout << htree[i].weight << ": " << huffmanCode[i] << std::endl;
	// 	}
	*/

	delete[]weight;
	delete[]huffmanCode;
}

main.cpp

#include <bits/stdc++.h>
#include "TreeNode.h"
#include "MyTree.h"
#include "Huffman.h"
using namespace std;

int main()
{
	MyTree myTree("ABC@@DE@G@@F@@@");
	myTree.preOrderTraverse();//ABCDEGF
	cout << endl;
	myTree.inOrderTraverse();//CBEGDFA
	cout << endl;
	myTree.postOrderTraverse();//CGEFDBA
	cout << endl;
	cout << myTree.countLeaf() << endl;//3
	cout << myTree.countHeight() << endl;//5

	MyTree myThreadedTree(myTree);
	cout << myThreadedTree.isThreadedTree() << endl;//0
	myThreadedTree.inOrderThreading();
	cout << myThreadedTree.isThreadedTree() << endl;//1
	myThreadedTree.inOrderTraverse();//CBEGDFA
	cout << endl;

	TreeNode n = myThreadedTree.locateNode('G');
	myThreadedTree.preNode(n).printNode();//E
	cout << endl;
	myThreadedTree.nextNode(n).printNode();//D

	cout << endl;	int v[] = {2,7,5,4};
	HuffmanTree hTree(4, v);
	hTree.printHuffmanCodes();
	/*
	7:0
	5:10
	4:111
	2:110
	*/

	return 0;
}

测试结果

结果如图所示:

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值