遍历
递归遍历:
递归前序遍历
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.最优二叉树(哈夫曼树)
哈夫曼树的构造(总权值要最小):
未完待续