【数据结构】树相关例题(C/C++含注释)

一、二叉树的创建及遍历

【问题描述】

​ 给出一个按照先序遍历得出的字符串,’#’ 代表空的子节点,大写字母代表节点内容。请通过这个字符串建立二叉树,并分别采用“递归”和“非递归”的先序、中序、后序遍历的算法分别输出每一个非空节点。

【输入形式】

​ 输入只有一行,包含一个字符串S,用来建立二叉树。保证S为合法的二叉树先序遍历字符串,节点内容只有大写字母,且S的长度不超过100。

【输出形式】

​ 共有6行,每一行包含一串字符,表示分别按递归和非递归的先序、中序、后序遍历得出的节点内容,每个字母后输出一个空格。请注意行尾输出换行。

【样例输入】

ABC##DE#G##F###

【样例输出】

扫描二维码关注公众号,回复: 14214475 查看本文章

A B C D E G F

C B E G D F A

C G E F D B A

A B C D E G F

C B E G D F A

C G E F D B A

【完整代码】

#include<iostream>
#include<cstdio>
#include<stack>
using namespace std;
//构建二叉树
typedef struct BiNode
{
    
    
	char date;
	BiNode* LChild;
	BiNode* RChild;
}*Bitree;
//递归创建树
void CreateBitree(Bitree &bt)
{
    
    
	char ch = getchar();
	if (ch == '#') bt = NULL;
	else
	{
    
    
		bt = new BiNode;
		bt->date = ch;
		CreateBitree(bt->LChild);
		CreateBitree(bt->RChild);
	}
}
//前序递归遍历
void PreOrder(Bitree root)
{
    
    
	if (root != NULL)
	{
    
    
		cout<<root->date<<" ";
	    PreOrder(root->LChild);
		PreOrder(root->RChild);
	}
}
//非递归前序遍历
void FPreOrder(Bitree root)
{
    
    
	stack<BiNode*> s;
	BiNode* cur = root;
	while (cur != NULL)
	{
    
    
		cout<< cur->date <<" ";
		s.push(cur);
		if (cur->LChild != NULL)
		{
    
    
			cur = cur->LChild;
		}
		else if (!s.empty())
		{
    
    
			while (!s.empty())
			{
    
    
				cur = s.top();
				s.pop();
				cur = cur->RChild;
				if (cur != NULL)
				{
    
    
					break;
				}
			}
		}
		else cur = NULL;
	}
}
//中序递归遍历
void InOrder(Bitree root)
{
    
    
	if (root!= NULL)
	{
    
    
		InOrder(root->LChild);
		cout << root->date << " ";
		InOrder(root->RChild);
	}
}
//非递归中序遍历
void FInOrder(Bitree root)
{
    
    
	stack<BiNode*> s;
	BiNode* cur = root;
	while (cur != NULL)
	{
    
    
		s.push(cur);
		if (cur->LChild != NULL)
		{
    
    
			cur = cur->LChild;
		}
		else if (!s.empty())
		{
    
    
			while (!s.empty())
			{
    
    
				cur = s.top();
				cout << cur->date << " ";
				s.pop();
				cur = cur->RChild;
				if (cur != NULL)
				{
    
    
					break;
				}
			}
		}
		else cur = NULL;
	}
}
//后续递归遍历
void PostOrder(Bitree root)
{
    
    
	if (root != NULL)
	{
    
    
		PostOrder(root->LChild);
		PostOrder(root->RChild);
		cout << root->date<<" ";
	}
}
//非递归后续遍历
void FPostOrder(Bitree root)
{
    
    
	stack<BiNode*> s;
	BiNode* p = root;
	BiNode* r = NULL;
	while (p || !s.empty())
	{
    
    
		if (p)
		{
    
    
			s.push(p);
			p = p->LChild;
		}
		else
		{
    
    
			p = s.top();
			if (p->RChild && p->RChild != r)
			{
    
    
				p = p->RChild;
			}
			else
			{
    
    
				s.pop();
				cout << p->date << " ";
				r = p;
				p = NULL;
			}
		}
	}
}

int main()
{
    
    
	Bitree root;
	//创建二叉树
	CreateBitree(root);
	//递归前序遍历
	PreOrder(root);
	cout << endl;
	//递归中序遍历
	InOrder(root);
	cout << endl;
	//递归后序遍历
	PostOrder(root);
	cout << endl;
	//非递归前序遍历
	FPreOrder(root);
	cout << endl;
	//非递归中序遍历
	FInOrder(root);
	cout << endl;
	//非递归后序遍历
	FPostOrder(root);
	return 0;
}

二、二叉树结点的共同祖先问题

【问题描述】假设二叉树采用二叉链表方式存储,root指向根结点,p所指结点和q所指结点为二叉树中的两个不同结点,且互不成为根到该结点的路径上的点,编程求解距离它们最近的共同祖先。

【输入形式】二叉树的前序和中序遍历序列,用以创建该二叉树的链式存储结构;以及二叉树的两个结点数据 x 和 y

【输出形式】结点数据值为 x 和结点数据值为 y 的最近的共同祖先,若没有共同祖先则输出NULL

【样例输入】

GABDCEF

BDAEFCG

DF

【样例输出】

A

【完整代码】

#include<iostream>
#include<stdio.h>
using namespace std;
//构建二叉树
typedef struct BiNode
{
    
    
    char date;
    BiNode* LChild;
    BiNode* RChild;
}*BiTree;
//寻找祖先
BiNode * SearchAncientNode(BiTree root,char p,char q)
{
    
    
    if (root == NULL) return NULL;
    //判断待查找的节点是否为根节点
    else if (root->date == p || root->date == q)
    {
    
    
        return root;
    }
    else
    {
    
    
        //递归查找祖先
        BiNode* Left = SearchAncientNode(root->LChild, p, q);
        BiNode* Right = SearchAncientNode(root->RChild, p, q);
        //左右子树均为空
        if (Left == NULL && Right == NULL)
        {
    
    
            return NULL;
        }
        //左右子树均不为空
        else if (Left!=NULL && Right!=NULL)
        {
    
    
            return root;
        }
        //左右子树有一个不为空
        else
        {
    
    
            if (Left)
            {
    
    
                return Left;
            }
            else
            {
    
    
                return Right;
            }
        }
    }
}
//判断是否为共同祖先
void IsSearchAncientNode(BiTree root, char p, char q)
{
    
    
    if (SearchAncientNode(root, p, q))
    {
    
    
        if (SearchAncientNode(root, p, q)->date == p ||SearchAncientNode(root,p,q)->date== q)
        {
    
    
            cout << "NULL" << endl;
        }
        else
        {
    
    
            cout << SearchAncientNode(root, p, q)->date << endl;
        }
    }
    else
    {
    
    
        cout << "NULL" << endl;
    }
}
//根据前序和中序序列创建二叉树
BiNode* CreateBiTree(char pre[], char in[], int preLeft, int preRight, int inLeft, int inRight)
{
    
    
    if (preLeft > preRight)  return NULL;
    int mid = -1;
    BiNode* root = new BiNode;
    for (int i = inLeft; i <= inRight; i++)
    {
    
    
        if (in[i] == pre[preLeft])
        {
    
    
            mid = i;
        }
    }
    root->date = in[mid];
    //递归创建
    root->LChild = CreateBiTree(pre, in, preLeft + 1, preLeft + mid - inLeft, inLeft, mid - 1);
    root->RChild = CreateBiTree(pre, in, preRight + mid - inRight + 1, preRight, mid + 1, inRight);
    return root;
}

int main()
{
    
    
    char pre[100], in[100];
    cin >> pre;
    cin >> in;
    char p, q;
    cin >> p >> q;
    int preLeft = 0, preRight = 0, inLeft = 0, inRight = 0;
    for (int i = 0; i < 100; i++)
    {
    
    
        if (pre[i] != '\0') preRight++;
        else break;
    }
    preRight = preRight - 1;
    inRight = preRight;
    BiTree root = CreateBiTree(pre, in, preLeft, preRight, inLeft, inRight);
    //输出最后结果
    IsSearchAncientNode(root, p, q);
    return 0;
}

三、哈夫曼编码

【问题描述】读入n个字符所对应的权值,自底向上构造一棵哈夫曼树,自顶向下生成每一个字符对应的哈夫曼编码,并依次输出。另,求解某字符串的哈夫曼编码,求解某01序列的译码。

【输入形式】输入的第一行包含一个正整数n,表示共有n个字符需要编码。其中n不超过100。第二行中有n个用空格隔开的正整数,分别表示n个字符的权值,依次按照abcd…的默认顺序给出。然后是某字符串和某01序列。

【输出形式】前n行,每行一个字符串,表示对应字符的哈夫曼编码。然后是某字符串的哈夫曼编码,某01序列的译码。

【注意】保证每次左子树比右子树的权值小;如出现相同权值的,则先出现的在左子树,即下标小的在左子树。

【样例输入】

8
5 29 7 8 14 23 3 11

aabchg

00011110111111001

【样例输出】

0001
10
1110
1111
110
01
0000
001

000100011011100010000

acdef

【完整代码】

#include<iostream>
#include<stack>
#include<vector>
#define maxsize 300
using namespace std;
//创建哈夫曼树
struct HFNode
{
    
    
	int weight;    //权重
	int parent;    //双亲
	int leftChild; //左子树
	int rightChild;//右子树
};
//初始化哈夫曼树
void InitalHFTree(HFNode HFTree[])
{
    
    
	for (int i = 0; i < maxsize; i++)
	{
    
    
		HFTree[i].leftChild = 0;
		HFTree[i].rightChild = 0;
		HFTree[i].parent = 0;
		HFTree[i].weight =-1;
	}
}
//获得最小值
void Getmin(HFNode HFTree[], int& s1, int& s2)
{
    
    
	int min1 = 10000;
	int i = 1;
	//找寻目前第一个最小值
	while (HFTree[i].weight!=-1)
	{
    
    
		if (HFTree[i].weight < min1 && HFTree[i].parent == 0)
		{
    
    
			min1 = HFTree[i].weight;
			s1 = i;
		}
		i++;
	}
	int min2 = 10000;
	i = 1;
	//找寻目前第二个最小值
	while (HFTree[i].weight != -1)
	{
    
    
		if (HFTree[i].weight < min2 && i != s1 && HFTree[i].parent == 0)
		{
    
    
			min2 = HFTree[i].weight;
			s2 = i;
		}
		i++;
	}
}
//构造哈夫曼树
void CreateHFTree(HFNode HFTree[], int& num)
{
    
    
	int top = num + 1;
	for (int i = 1; i < num; i++)
	{
    
    
		int s1; int s2;
		//每次找最小的两个
		Getmin(HFTree, s1, s2);
		//更新哈夫曼树
		HFTree[top].weight = HFTree[s1].weight + HFTree[s2].weight;
		HFTree[top].leftChild = s1;
		HFTree[top].rightChild = s2;
		HFTree[s1].parent = top;
		HFTree[s2].parent = top;
		top++;
	}
	num = top - 1;
}
//为每个元素构造哈夫曼编码
void  GetHuffmanCode(HFNode HFTree[],int num,int i,char str[])
{
    
    
	num = (num + 1) / 2;
	stack<char> s;
	int j = HFTree[i].parent;
	//为字母进行01序列编码
	while (j)
	{
    
    
		if (HFTree[j].leftChild == i) s.push('0');
		else if (HFTree[j].rightChild == i) s.push('1');
		i = j;
		j = HFTree[j].parent;
	}
	int k = 0;
	while (!s.empty())
	{
    
    
		str[k] = s.top();
		s.pop();
		k++;
	}
	str[k] = '\0';
}
//根据输入的01序列判断原字符序列
void GetHuffmandecode(HFNode HFTree[], int num, string s)
{
    
    
	int i = 0;
	while (i<(signed)s.size())
	{
    
    
		int cur = num;
		while (HFTree[cur].leftChild!=0&& HFTree[cur].rightChild!=0)
		{
    
    
			if (s[i] == '0')
			{
    
    
				cur = HFTree[cur].leftChild;
			}
			else if (s[i] == '1')
			{
    
    
				cur = HFTree[cur].rightChild;
			}
			i++;
		}
		char ch = 'a' + cur - 1;
		cout << ch;
	}
}

int main()
{
    
    
	int num, arr[maxsize];
	cin >> num;
	for (int i = 0; i < num; i++) cin >> arr[i];
	HFNode HFTree[maxsize];
	InitalHFTree(HFTree);
	//哈夫曼树权重初始化
	for (int i = 0; i < num; i++)
	{
    
    
		HFTree[i + 1].weight = arr[i];
	}
	//创建哈夫曼树
	CreateHFTree(HFTree, num);
	string s1;
	cin >> s1;
	string s2;
	cin >> s2;
	char str[100];
	//为字母进行编码
	for (int i = 0; i <(num+1)/2; i++)
	{
    
    
		GetHuffmanCode(HFTree, num, i+1, str);
		cout << str << endl;
	}
	cout << endl;
	for (int i = 0; i < (signed)s1.size(); i++)
	{
    
    
		int j = s1[i] - 96;
		GetHuffmanCode(HFTree, num,j, str);
		cout << str;
	}
	cout << endl << endl;
	//根据输入的01序列推导原字符串
	GetHuffmandecode(HFTree, num, s2);
	return 0;
}

四、二叉树左右子树交换操作

【问题描述】二叉树按照二叉链表的方式存储。编写程序,计算二叉树中叶子结点的数目并输出;编写程序,将二叉树的左右子树进行交换,并输出交换后的二叉树的后序遍历序列。

【输入形式】二叉树的前序遍历序列,空指针的位置输入字符#

【输出形式】叶子结点的数目;左右子树交换后,后序遍历的序列,空子树的位置输出字符#

【样例输入】

ABE##F##CG###

【样例输出】

3

###GC##F##EBA

【完整代码】

#include<iostream>
using namespace std;
//构建二叉树类
class bintree
{
    
    
private:
	struct node
	{
    
    
		char data;
		node * left_child;  //左子树
		node * right_child; //右子树
		//构造函数初始化
		node()
		{
    
    
		    left_child = right_child = NULL;
        }
	}*root, *p;
	void input(node ** r);
	//统计叶子节点个数
	int leaf_count(node * r);
	//交换左右子树
	void swap_child(node ** r);
	void Show(node * r);
public:
	bintree();
	void prompt()
	{
    
    
	    input(&root);
    }
	int lcount()
	{
    
    
	    return leaf_count(root);
    }
	void swap_c()
	{
    
    
	    swap_child(&root);
    }
	void show()
	{
    
    
	    Show(root);
	    cout<<endl;
    }
};
//根据前序遍历序列构建二叉树
void bintree::input(node ** r)
{
    
    
	char d;
	cin>>d;
	if (d != '#')
	{
    
    
		*r = new node;
		(*r)->data = d;
		input(&(*r)->left_child);
		input(&(*r)->right_child);
	}
}
//初始化
bintree::bintree()
{
    
    
	root = NULL;
	p = NULL;
}
//统计叶子节点个数
int bintree::leaf_count(node * r)
{
    
    
	if (r == NULL)
		return 0;
	else if (r->left_child == NULL && r->right_child == NULL)
		return 1;
	else
		return leaf_count(r->left_child) + leaf_count(r->right_child);
}
//交换左右子树
void bintree::swap_child(node ** r)
{
    
    
	node * temp;
	if (*r != NULL)
	{
    
    
	    //通过temp交换
		temp = (*r)->left_child;
		(*r)->left_child = (*r)->right_child;
		(*r)->right_child = temp;
        //递归交换
		swap_child(&(*r)->left_child);
		swap_child(&(*r)->right_child);
	}
}
//输出
void bintree::Show(node * r)
{
    
    
	if (r != NULL)
	{
    
    
		Show(r->left_child);
		Show(r->right_child);
		cout<<r->data;
	}
	else
		cout << '#';
}

int main()
{
    
    
	bintree bt;
	//初始化
	bt.prompt();
	//输出叶子节点个数
	cout<<bt.lcount()<< endl;
	//左右子树交换
	bt.swap_c();
	//输出后序序列
	bt.show();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_44528283/article/details/123917120