二叉树

遍历

递归遍历:

递归前序遍历 
void preorder(Node *root)
{
	if(!root)	return;
	printf("%d ", root->val);// 数据 
	preorder(root->left);  //左子树 
	preorder(root->right); //右子树 
}
-------------------------------------
递归中序遍历 
void inorder(Node *root)
{
	if(!root)	return;
	preorder(root->left);  //左子树 
	printf("%d ", root->val);//数据 
	preorder(root->right); //右子树 
}
-------------------------------------
递归后续遍历 
void postorder(Node *root)
{
	if(!root)	return;	   
	preorder(root->left); //左字数 
	preorder(root->right);//右子树 
	printf("%d ", root->val); //数据 
}

非递归遍历

不想学,麻烦!

创建二叉树

知道先序序列与中序序列,创建出二叉树:
如果忘记了就看这里https://blog.csdn.net/u010189308/article/details/79807613
照着它写以下…

typedef struct BiTreeNode
{
	char date;
	struct BiTreeNode *lchild, *rchile;
}BiTreeNode, *BiTree;

BiTree PreInOrder(char preord[], char inord[], int i, int j, int k, int h)
{
	//先序序列中从 i到 j,中序序列中从 k到 h,建立一棵二叉树放在 *t中 
	Bitree t;
	int m;
	t = (BiTreeNode *) malloc (sizeof(BiTreeNode));
	t->date  = preord[i] 	// m 为此时的根结点 
	m = k;
	while(inord[m]! == preord[i]) m++;	//在中序序列定位根结点
	
	/*递归调用建立左子树*/ 
	if(m == k) t -> lchild = NULL; //左子树为空 
	else t-> lchile = PreInOrder(preord, inord, i+1, i+m-k, k, m-1);
	
	/*递归调用建立右子树*/ 
	if(m == h) t-> rchile = NULL; //右子树为空
	else t-> rchile = PreInOrder(preord, inord, i+m-k+1, j, m+1, h);
	
	return t;
}

BiTree CreatBiTree(char preord[], char inord, int n) 
{/* n为二叉树结点的个数,建立 二叉树放在root(根)中*/ 
	BiTree root;
	if(n<=0) root = NULL;
	else root = PreInOrder(preord[], inord, 0, n-1, 0, n-1);
	
	return root;
}

下面的代码是根据上面的思维写出来的,但并不是创建二叉树
只是想上面一样通过前中序列进行分割,但不创建二叉树
就单纯的分割来解决问题

#include<bits/stdc++.h>
using namespace std;
string a, b;
void dfs(string x, string y){ //x为中序 y为前序 对y进行分割,因为y第一个是根结点
	if(!(int)y.size()) return;//递归边界 
	int pos = x.find(y[0]);//在中序遍历中找到根节点 
	dfs(x.substr(0, pos), y.substr(1, pos));//递归1 
	dfs(x.substr(pos + 1), y.substr(pos + 1));//递归2 
	printf("%c", y[0]);//再输出根节点  放在这是输出后序 放上边是其他序
	return;//陋习qwq 
}
int main(){
	cin >> a >> b;
	dfs(a, b);
	system("pause");//日常防伪代码 
	return 0;
}
/* 假设:string s = "0123456789";

string sub1 = s.substr(5); //只有一个数字5表示从下标为5开始一直到结尾:sub1 = "56789"

string sub2 = s.substr(5, 3); //从下标为5开始截取长度为3位:sub2 = "567"*/

知道后序序列与中序序列,创建出二叉树:

有时间再添加

这里有个二叉树的题目,
做题时候不一定要创建结构体
看它的题解类似与用结构体创建,很方便!
https://www.luogu.com.cn/problem/P1305
题解

#include<iostream> 
#include<cstdio>//不管,就是喜欢这个头文件,长得太好看了 
using namespace std;
struct programmer//struct定义,好把树的节点连接起来,具体可以看代码呀 
{
	char lc;//左孩子X1(left child,简称lc) 
	char rc;//右孩子X1(right child,简称rc) 
}lt[130];//数组,这个十分重要,一会儿输入字符的时候还要用这个串起来,其实真正起作用的只有lt[73]~lt[122],说这个是为了防止一些人不多想,方便理解的

char h,h1;//储存一会儿要输入的节点,多定义一个h1是为了一会儿将根节点保留下来先代入函数
void sm(char x)//我是谁,我杀了谁,谁又杀了我 
{
	if(x=='*') return;//如果是*说明此乃空节点,那就不用再往下探了 
	cout<<x;//先把它给输出出来,碰着一个就踢出去一个,输出的顺序是可以保障的,至于为什么可以看后面,我解释了 
	sm(lt[x].lc);//找到他的左孩子,继续往下探(如果左孩子是*的话,会返回的,可以看上一句的上一句) 
	sm(lt[x].rc);//找到他的右孩子,继续向下探索 
/*这里我举个例子: 例如输入abc和bcd,a的ASC码是73,所以lt[73].lc是b(ASC码74),接着再从b开始探,lt[74].lc之前有过输入,是个c。再从序
号为'c'(75)的lt数组继续往下探索,一探索到*,就会往回跑。回到c数组的rc,往回探,所以顺序问题可以保证,要是还是理解不了,可以画画试试,亲测有
效。这个函数和输入其实就是在数组的各个部分之间不断穿梭,用字符的ASC码值作为连接节点的线,数组的左右孩子就是下一个要寻找的数组的代号*/ 
}
int main()
{
	int n;//n在题目上说了,输入几个节点 
	scanf("%d",&n);//为了方便大家观看,我把输入拆成三部分 
	cin>>h1;//输入第一个字母,第一个字母比较特殊,所以单独输入 
	cin>>lt[h1].lc;//左孩子,h1所代表的字符再次会转换为ASC码 
	cin>>lt[h1].rc;//右孩子,道理和上面相同,就不用我多费口舌了 
	for(int i=2;i<=n;i++)//这里大家都懂的吧,输入 
	{
		cin>>h;
		cin>>lt[h].lc;
		cin>>lt[h].rc;
	}
	sm(h1);//进入函数,用的是递归,但我也是AC了才敢来发题解的 
	return 0;
}

.
.

线索二叉树

数据结构p157页有张简便的图

定义:

typedef struct BiThrNode
{
	ElemType date;
	struct BiThrNode * lchild, *rchild;
	int ltag, rtag;
}BiThrNode, *BithrTree;

二叉树的线索化:遍历一个二叉树,遍历过程中,将其线索化!

中序线索二叉树:

BithrTree pre;//全局变量pre始终指向刚才访问的那个结点
 
这是前期的准备和启动线索话 
int InOrderThrTree(BithrTree *head, BithrTree bt)//head为头结点 bt为根结点 
{
	*head = (BiThrTree) malloc (sizeof(BiThrNode));
	if(*head == NULL) return 0;//创建空间失败
	(*head)->ltag = 0;
	(*head)->rtag = 1;
	(*head)->rchild = *head; //右指针回指 
	if(bt == NULL) (*head)->lchile = *head;//二叉树为空,左指针回指
	else
	{
		(*head)->lchild = bt;//头结点的左孩子指向二叉树的根结点 
		pre = *head;
		InTreading(bt); //中序遍历二叉树线索化
		pre->rchild = *head;
		pre->rtag = 1;   //最后一个结点线索化 
		(*head)->rchild = pre 
	} 
	return 1;
} 

void InThreading(BiThrTree p)//中序遍历二叉树线索化
{
	if(p)
	{
		InThreading(p->lchild);//走p的左边 
		
		if(p->lchild == NULL)//p无左孩子,左指针线索化 
		{p->ltag = 1; p->lchild = pre;}
		
		if(pre->rchild == NULL)//pre无右孩子,右指针线索化 
		{pre->rtag = 1; pre->rchild = p;}
		
		pre = p;
		InThreading(p->rchild);//走p的右边 
	}
}

哈夫曼树 p167

eg:给n个叶子 组合起来的哈夫曼树的结点个数为2n-1
权值:
在这里插入图片描述
1.最优二叉树(哈夫曼树)

哈夫曼树的构造(总权值要最小):
在这里插入图片描述
未完待续

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值