第五章树和二叉树(5.1-5.3)

目录

5.1树和二叉树的定义

5.1.1树的定义

n(n≥0)个结点的有限集合。

当n=0时,称为空树;

任意一棵非空树满足以下条件:

⑴ 有且仅有一个特定的称为根的结点;

⑵ 当n>1时,除根结点之外的其余结点被分成m(m>0)个互不相交的有限集合T1,T2,…
,Tm,其中每个集合又是一棵树,并称为这个根结点的子树。

第五章树和二叉树(5.1-5.3)

第五章树和二叉树(5.1-5.3)

5.1.2树的基本术语

  1. 结点的度:结点所拥有的子树的个数。

  2. 树的度:树中各结点度的最大值。

  3. 叶子结点:度为0的结点,也称为终端结点。

  4. 分支结点:度不为0的结点,也称为非终端结点。

  5. 孩子、双亲:树中某结点子树的根结点称为这个结点的孩子结点,这个结点称为它孩子结点的双亲结点;

  6. 兄弟:具有同一个双亲的孩子结点互称为兄弟。

  7. 路径:如果树的结点序列n1, n2, …, nk有如下关系:结点ni是ni+1的双亲(1<=i<k),则把n1, n2,…, nk称为一条由n1至nk的路径;路径上经过的边的个数称为路径长度。

  8. 祖先、子孙:在树中,如果有一条路径从结点x到结点y,那么x就称为y的祖先,而y称为x的子孙。

  9. 结点所在层数:根结点的层数为1;对其余任何结点,若某结点在第k层,则其孩子结点在第k+1层。

  10. 树的深度:树中所有结点的最大层数,也称高度。

  11. 层序编号:将树中结点按照从上层到下层、同层从左到右的次序依次给他们编以从1开始的连续自然数。

  12. 有序树、无序树:如果一棵树中结点的各子树从左到右是有次序的,称这棵树为有序树;反之,称为无序树。

  13. 森林:m (m≥0)棵互不相交的树的集合。

    第五章树和二叉树(5.1-5.3)

5.1.3二叉树的定义

二叉树(Binary Tree)是n(n≥0)个结点所构成的集合,它或为空树(n= 0); 或为非空树,

对于非空树T:

(1) 有且仅有一个称之为根的结点;

(2)除根结点以外的其余结点分为两个互不相交的子集T1和T2, 分别称为T的左子树和右子树,且兀和乃本身又都是二叉树。二叉树与树一样具有递归性质,二叉树与树的区别主要有以下两点:

(1 )二叉树每个结点至多只有两棵子树(即二叉树中不存在度大千2 的结点);

(2). 二叉树的子树有左右之分,其次序不能任意颠倒。

二叉树的递归定义表明二叉树或为空,或是由一个根结点加上两棵分别称为左子树和右子树的、互不相交的二叉树组成。由千这两棵子树也是二叉树,则由二叉树的定义,它们也可以是空树

5.2案例引入

案例5.1:数据压缩问题

#include<iostream>
#include<cstring>
#include<string>
using namespace std;
struct Num
{
	char ch;
	int num;
}an[7000], temp;
void sort1(Num *bn)
{
	Num te;
	int i, j;
	for (j = 0; j<26; j++)
		for (i = 0; i < 25; i++)
		{
			if (bn[i].num < bn[i + 1].num)
			{
				te = bn[i];
				bn[i] = bn[i + 1];
				bn[i + 1] = te;
			}
		}
}
void sort2(Num *bn, int n)
{
	Num te;
	int i, j;
	for (j = 0; j<26; j++)
		for (i = 0; i < 25; i++)
		{
			if (bn[i].ch > bn[i + 1].ch&&bn[i + 1].num > 0)
			{
				te = bn[i];
				bn[i] = bn[i + 1];
				bn[i + 1] = te;
			}
		}
}
typedef struct
{
	int weight;
	int parent, lchild, rchild;
	int vis;
	char ch;
	char strc[60];
	int len;
	int num;
}HTNode, *HuffmanTree; 
void Select(HuffmanTree &HT, int k, int &s1, int &s2)
{
	int i;
	HTNode h1, h2;
	int t1, t2;
	t1 = t2 = 0;
	h1 = HT[1];
	h1.weight = 999999;
	for (i = 1; i <= k; i++)
	{
		if (HT[i].weight <= h1.weight &&HT[i].vis == 0)
		{
			h1 = HT[i];
			t1 = i;
		}
	}
	h2 = HT[2];
	h2.weight = 999999;
	for (i = 1; i <= k; i++)
	{
		if (HT[i].weight <= h2.weight&&t1 != i&&HT[i].vis == 0)
		{
			h2 = HT[i];
			t2 = i;
		}
	}
	if (h1.weight == h2.weight&&HT[t1].num > HT[t2].num)
	{
		int temp;
		temp = t1;
		t1 = t2;
		t2 = temp;
	}
	s1 = t1;
	s2 = t2;
	HT[s1].vis = 1;
	HT[s2].vis = 1;
	return;
}
void code(HuffmanTree &HT, int len, char str[], int n, char cc)
{
	int i;
	for (i = 0; i < len - 1; i++)
		HT[n].strc[i] = str[i];
	HT[n].strc[i] = cc;
	HT[n].strc[i + 1] = '\0';
	if (HT[n].lchild != 0)
		code(HT, len + 1, HT[n].strc, HT[n].lchild, '0');
	if (HT[n].rchild != 0)
		code(HT, len + 1, HT[n].strc, HT[n].rchild, '1');
}
void CreateHuffmanTree(HuffmanTree &HT, int n, char *str, int n1)
{
	int s1, s2;
	s1 = s2 = 0;
	if (n <= 1)
		return;
	int m = 2 * n - 1;
	HT = new HTNode[m + 1];
	for (int i = 1; i <= m; i++)
	{
		HT[i].parent = 0; HT[i].lchild = 0; HT[i].rchild = 0; HT[i].vis = 0; HT[i].len = 0; HT[i].num = i; HT[i].weight = 0;
	}
	for (int i = 1; i <= n; i++)
	{
		HT[i].weight = an[i - 1].num;
		HT[i].ch = an[i - 1].ch;
	}
	for (int i = n + 1; i <= m; i++)
	{
		Select(HT, i - 1, s1, s2);
		HT[s1].parent = i;
		HT[s2].parent = i;
		HT[i].lchild = s1;
		HT[i].rchild = s2;
		HT[i].weight = HT[s1].weight + HT[s2].weight;
	}
	int len = HT[m].len;
	HT[m].strc[len] = '1';
	if (HT[m].lchild)
		code(HT, 1, "", HT[m].lchild, '0');
	if (HT[m].rchild)
		code(HT, 1, "", HT[m].rchild, '1');
	return;
}
 
int main()
{
	HuffmanTree h;
	int n, n1;
	char str[700], str2[700];
	while (cin >> str)
	{
		if (str[0] == '0'&&str[1] == '\0')
			break;
		n1 = 0;
		for (int i = 0; i < 27; i++)
		{
			an[i].num = 0;
			an[i].ch = 'a' + i;
		}
		n = strlen(str);
		for (int i = 0; i < n; i++)
		{
			an[str[i] - 'a'].num++;
			str2[i] = str[i];
			str2[i + 1] = '\0';
		}
		sort1(an);
		for (int i = 0; i < 26; i++)
		{
			if (an[i].num != 0)
				n1++;
		}
		sort2(an, n1);
		CreateHuffmanTree(h, n1, str, n1);
		if (n1 == 1)
		{
			h = new HTNode[3];
			h[1].weight = n; h[1].parent = h[1].lchild = h[1].rchild = 0;
			h[1].ch = str[0]; h[1].strc[0] = '0'; h[1].strc[1] = '\0';
		}
		int f = 0;
		for (int i = 0; i < 26; i++)
			if (an[i].num > 0)
			{
				f++;
				cout << an[i].ch << ":" << an[i].num ;
				if (f == n1)
					cout << endl;
				else
					cout << " ";
			}
		for (int i = 1; i <= 2 * n1 - 1; i++)
		{
			cout << i << " " << h[i].weight << " " << h[i].parent << " " << h[i].lchild << " " << h[i].rchild << endl;
		}
		for (int i = 1; i < n1; i++)
			cout << h[i].ch << ":" << h[i].strc << " ";
		cout << h[n1].ch << ":" << h[n1].strc;
		cout << endl;
 
		for (int i = 0; i < n; i++)
		{
			for (int j = 1; j <= n1; j++)
				if (h[j].ch == str[i])
					cout << h[j].strc;
		}
		cout << endl;
		cout << str << endl;
 
		for (int i = 1; i <= 2 * n1 - 1; i++)
		{
			h[i].parent = 0; h[i].lchild = 0; h[i].rchild = 0; h[i].vis = 0; h[i].len = 0; h[i].num = i;
		}
	}
	return 0;
}

案例5.2:利用二叉树求解表达式的值

#include <iostream>
using namespace std;
//定义表达式树
typedef int TreeElemType;
typedef struct TreeNode {
	TreeElemType data;
	struct TreeNode* lchild, *rchild;
}TreeNode,*ExpTree;
//定义树栈
typedef struct ETStackNode {
	ExpTree ETStackdata;
	struct ETStackNode* next;
}ETStackNode,*ETLinkStack;
//定义算符栈
typedef char ElemType;
typedef struct ChStack {
	ElemType ChStackdata;
	struct ChStack* next;
}ChStackNode, *ChLinkStack;
//算符优先级比较表
char CList[7][7] =
{
	{ '>','>','<','<','<','>','>' },
	{ '>','>','<','<','<','>','>' },
	{ '>','>','>','>','<','>','>' },
	{ '>','>','>','>','<','>','>' },
	{ '<','<','<','<','<','=',' ' },
	{ '>','>','>','>',' ','>','>' },
	{ '<','<','<','<','<',' ','=' },
};
//定义七种算符
char *Op = "+-*/()#";
//树栈初始化
void EXTInitStack(ETLinkStack &LS)
{
	LS = NULL;
}
// 树栈添加元素
void EXTPush(ETLinkStack &LS, ExpTree ET)
{
	ETStackNode* p = new ETStackNode;
	p->ETStackdata = ET;
	p->next = LS;
	LS = p;
}
//树栈弹出栈顶元素
void EXTPop(ETLinkStack &LS, ExpTree &ET)
{
	if (LS == NULL) return;
	ET = LS->ETStackdata;
	ETStackNode* p = LS;
	LS = LS->next;
	delete p;
}
//树栈获取栈顶元素
ExpTree EXTGetTop(ETLinkStack &LS)
{
	if (LS) return LS->ETStackdata;
}
//算符栈初始化
void ChInitStack(ChLinkStack &CS)
{
	CS = NULL;
}
//算符栈添加元素
void ChPush(ChLinkStack& CS, ElemType e)
{
	ChStackNode* p = new ChStackNode;
	p->ChStackdata = e;
	p->next = CS;
	CS = p;
}
//算符栈弹出栈顶元素
void ChPop(ChLinkStack& CS, ElemType &e)
{
	if (CS == NULL) return;
	e = CS->ChStackdata;
	ChStackNode* p = CS;
	CS = CS->next;
	delete p;
}
//算符栈获取栈顶元素值
ElemType ChGetTop(ChLinkStack &CS)
{
	if (CS != NULL) return CS->ChStackdata;
}
//判断ch是否为算符
bool In(char ch)
{
	int i = 0;
	while (Op && Op[i] != ch)
		i++;
	return i < 7;
}
//创建表达式树结点
//以T为根节点,*lchild,*rchild分别为左右孩子
void CreateExpTree(ExpTree &T, TreeNode* lchild, TreeNode* rchild, TreeElemType data)
{
	T = new TreeNode;
	T->data = data;
	T->lchild = lchild;
	T->rchild = rchild;
}
//将数值型字符串转换成int型数字
int Atoi(char *str)
{
	int res = 0;
	while (*str)
		res = res * 10 + (*str++ - '0');
	return res;
}
//判断算符优先级
char Precede(char c1, char c2)
{
	int i = 0, j = 0;
	while (Op[i] && Op[i] != c1)
		i++;
	while (Op[j] && Op[j] != c2)
		j++;
	return CList[i][j];
}
//表达式树的创建算法
ExpTree InitExpTree()
{
	ETLinkStack EXPT; 
	ChLinkStack OPTR;
	EXTInitStack(EXPT);
	ChInitStack(OPTR);
	ChPush(OPTR, '#');
	char ch;
	cin >> ch;
	while (ch != '#' || ChGetTop(OPTR) != '#')
	{
		if (!In(ch))
		{
			char data[20] = { '\0' };
			int i = 0;
			data[i++] = ch;
			cin >> ch;
			while (!In(ch))
			{
				data[i++] = ch;
				cin >> ch;
			}

			ExpTree T;
			CreateExpTree(T, NULL, NULL, Atoi(data));
			EXTPush(EXPT, T);
		}
		else
		{
			switch (Precede(ChGetTop(OPTR),ch))
			{
			case '<':
				ChPush(OPTR, ch);
				cin >> ch;
				break;
			case '>':
				char theta;
				ChPop(OPTR, theta);
				TreeNode* t1, *t2;
				EXTPop(EXPT, t2); EXTPop(EXPT, t1);
				ExpTree T;
				CreateExpTree(T, t1, t2, theta);
				EXTPush(EXPT, T);
				break;
			case '=':
				ChPop(OPTR, theta);
				cin >> ch;
				break;
			}
		}
	}
	return EXTGetTop(EXPT);
}
// 中序遍历表达式树
/*
void InOrderTree(ExpTree T)
{
	if (T)
	{
		InOrderTree(T->lchild);
		if (T->lchild)
		{
			char ch = T->data;
			cout << ch;
		}
		else
			cout << T->data;
		InOrderTree(T->rchild);
	}
}
*/
//求值
int GetValue(char ch, int a, int b)
{
	switch (ch)
	{
	case '+':
		return a + b;
	case '-':
		return a - b;
	case '*':
		return a*b;
	case '/':
		return a / b;
	}
}
//遍历表达树进行表达式求值
int EvaluateExpTree(ExpTree T)
{
	int lvalue = 0, rvalue = 0;
	if (T->lchild == NULL&&T->rchild == NULL)
		return T->data;
	else
	{
		lvalue = EvaluateExpTree(T->lchild);
		rvalue = EvaluateExpTree(T->rchild);
		return GetValue(T->data, lvalue, rvalue);
	}
}
//主函数
int main()
{
	ExpTree T = InitExpTree();
	cout << EvaluateExpTree(T) << endl;
	return 0;
}

5.3树和二叉树的抽象数据类型定义

第五章树和二叉树(5.1-5.3)

第五章树和二叉树(5.1-5.3)

第五章树和二叉树(5.1-5.3)

上一篇:无线HT的意思


下一篇:C# 理解委托与事件