文章目录
1.二叉树的递归遍历
1.1前序递归遍历
void preorder(NODE *root)
{
if(root != 0)
{
printf("%c ", root->data);
preorder(root->lchild);
preorder(root->rchild);
}
}
1.2中序递归遍历
void midorder(NODE *root)
{
if(root != 0)
{
midorder(root->lchild);
printf("%c ", root->data);
midorder(root->rchild);
}
}
1.3后序递归遍历
void posorder(NODE *root)
{
if(root != 0)
{
posorder(root->lchild);
posorder(root->rchild);
printf("%c ", root->data);
}
}
2.二叉树的非递归遍历
2.1前序非递归遍历
void preorder(NODE *root)
{
NODE *stack[MAXN];
NODE *p = root;
int top = 0;
while(p != 0 || top > 0)
{
while(p != 0)
{
printf("%c ", p->data);
stack[top++] = p;
p = p->lchild;
}
if(top > 0)//栈非空
{
p = stack[--top];
p = p->rchild;
}
}
}
2.2中序非递归遍历
void midorder(NODE *root)
{
NODE *stack[MAXN];
NODE *p = root;
int top = 0;
while(p != 0 || top > 0)
{
while(p != 0)
{
stack[top++] = p;
p = p->lchild;
}
if(top > 0)//栈非空
{
p = stack[--top];
printf("%c ", p->data);
p = p->rchild;
}
}
}
//对比前序和中序非递归遍历代码,不难发现只是输出节点值得代码位置变了,其他代码都一样。
2.3后序非递归遍历
void posorder(NODE *root)//后序遍历非递归算法
{
NODE *stack[MAXN];
NODE *cur, *pre = 0;//cur为当前节点 pre为前一个访问的节点
int top = 0;
stack[top++] = root;//先将根节点入栈
while(top > 0)//栈非空
{
cur = stack[top-1];//使cur指向栈顶节点
if((cur->lchild == 0 && cur->rchild == 0) || (pre != 0 && (pre == cur->lchild || pre == cur->rchild)))
{
//如果当前结点没有孩子结点或者孩子节点都已被访问过
printf("%c ", cur->data);
top--;
pre = cur;
}
else
{
if(cur->rchild != 0)
stack[top++] = cur->rchild;
if(cur->lchild != 0)
stack[top++] = cur->lchild;
}
}
}
3.二叉树的层序遍历(即从上到下逐层遍历)
void levelorder(NODE *root)
{
NODE* que[MAXN];
NODE *p;
int tail = 0, top = 0;
que[tail++] = root;//根节点入队
while(tail != top)
{
p = que[top++];//出队
printf("%c ", p->data);
if(p->lchild != 0)
que[tail++] = p->lchild;
if(p->rchild != 0)
que[tail++] = p->rchild;
}
}
4.二叉树深度
树的深度:从根节点到叶子结点一次经过的结点形成树的一条路径,最长路径的长度为树的深度,根节点的深度为1。
int tree_depth(NODE *root)
{
if(root == 0)
return 0;
else
{
int depth, depth1=1, depth2=1;
depth1 += tree_depth(root->lchild);
depth2 += tree_depth(root->rchild);
depth = depth1 > depth2 ? depth1:depth2;
return depth;
}
}
区分一下树的高度:从叶子节点到根结点一次经过的结点形成树的一条路径,最长路径的长度为树的高度,叶子节点的深度为1。虽然同一棵树的深度和高度相同,但是具体到树的某个节点,其深度和高度是不一样的 。
5.二叉树的直径
树的直径(有时称为宽度)是两个叶子节点之间最长路径上的节点数。
int diameterOpt(NODE *root, int* height)
{//第二个参数是存储树的高度
int lh = 0, rh = 0;//左右子树的高度
int ldiameter = 0, rdiameter = 0;//左右子树的直径
if(root == NULL)
{
*height = 0;
return 0; //直径也为0
}
ldiameter = diameterOpt(root->left, &lh);
rdiameter = diameterOpt(root->right, &rh);
*height = max(lh, rh) + 1;
return max(lh + rh + 1, max(ldiameter, rdiameter));
}
6.二叉树的节点个数
int count_node(NODE *root)
{
if(root == 0)
return 0;
else
return count_node(root->lchild) + count_node(root->rchild) + 1;
}
7.二叉树的复制
NODE* copy_B_tree(NODE *root)
{
if(root == 0)
return 0;
NODE *p = 0;
p = (NODE*)malloc(sizeof(NODE));
p->data = root->data;
p->lchild = copy_B_tree(root->lchild);
p->rchild = copy_B_tree(root->rchild);
return p;
}
8.判断两棵二叉树是否相等
int equal_B_tree(NODE *root1, NODE *root2)
{
if(root1 == 0 && root2 == 0)
return 1;
if(root1 != 0 && root2 != 0)
if(root1->data == root2->data)
if(equal_B_tree(root1->lchild, root2->lchild) && equal_B_tree(root1->rchild, root2->rchild))
return 1;
return 0;
}
9.判断两棵二叉树是否是子树关系
bool HasSubtree(Node* root1, Node* root2)
{//判断root2是不是root1的一颗子树
bool res = false;
if(root1 != NULL && root2 != NULL) {
if(root1->data == root2->data)
res = IsSubtree(root1, root2);
if(!res)
res = HasSubtree(root1->lchild, root2);//判断是否是左子树的子树
if(!res)
res = HasSubtree(root1->rchild, root2);//判断是否是右子树的子树
}
return res;
}
bool IsSubtree(Node* root1, Node* root2) {
if(root2 == NULL)
return true;
if(root1 == NULL)
return false;
if(root1->data != root2->data)
return false;
return IsSubtree(root1->lchild, root2->left) && IsSubtree(root1->rchild, root2->right);
}
10.交换二叉树的所有左右节点
void exchange_node(NODE *root)
{
if(root != 0)
{
NODE *pl = 0, *pr = 0;
pl = root->lchild;
pr = root->rchild;
root->lchild = pr;
root->rchild = pl;
exchange_node(root->lchild);
exchange_node(root->rchild);
}
}
11.已知二叉树的前序和中序遍历结果建树
NODE* build_Btree(char *pre, char *mid, int len)
//已知前序遍历pre和中序遍历mid
{
NODE *root;
root = (NODE*)malloc(sizeof(NODE));
if(len == 0)
return root = 0;//len==0 表示无子节点
root->data = pre[0];
int i=0;
while(mid[i] != pre[0] && i < len)
i++;//找出左节点个数
root->lchild = build_Btree(pre+1, mid, i);//pre+1 跳过根节点
root->rchild = build_tree(pre+i+1, mid+i+1, len-i-1);
//pre+i+1 代表前序遍历右子树部分 mid+i+1代表中序遍历右子树部分
return root;
}
12.已知二叉树的后序和中序遍历结果建树
NODE* build_Btree(char *mid, char *pos, int len)
//已知中序遍历mid和后序遍历pos
{
NODE *root;
root = (NODE*)malloc(sizeof(NODE));
if(len == 0)
return root = 0;//len==0 表示无子节点
root->data = pos[len-1];
int i = 0;
while(mid[i] != pos[len-1] && i < len)
i++;//找出左节点个数
root->lchild = build_tree(mid, pos, i);
root->rchild = build_tree(mid+i+1, pos+i, len-i-1);
return root;
}
13. 将二叉搜索树转换为一个排序的双向链表
NODE *head = NULL;
NODE *tail = NULL;
NODE* Convert(NODE* root)
{//中序递归遍历
if(root == NULL)
return NULL;
//处理左子树
Convert(root->lchild);
//将根节点插到链表尾部
if(tail == NULL)
head = tail = root;//中序遍历的第一个节点
else
{
tail->rchild = root;
root->lchild = tail;
tail = root;
}
//处理右子树
Convert(root->rchild);
return head;
}
14.判断二叉树是否是平衡二叉树
//借助于求二叉树深度的函数(见4)
bool isbalance_tree(Node* root)
{
if(root == NULL)
return true;
return abs(tree_depth(root->lchild) - tree_depth(root->rchild)) <= 1 && isbalance_tree(root->lchild) && isbalance_tree(root->rchild);
}
15.判断一棵树是否是对称二叉树
//对称二叉树指镜像二叉树
bool isSymmetrical(Node* root)
{
if(root == NULL)
return true;
return Symmetrical(root->lchild, root->rchild);
}
bool Symmetrical(Node* root1, Node* root2)
{
if(root1 == NULL && root2 == NULL)
return true;
if(root1 != NULL && root2 != NULL)
return root1->data == root2->data && Symmetrical(root1->lchild, root2->rchild) && Symmetrical(root1->rchild, root2->lchild);
return false;
}
16.序列化和反序列化二叉树
//将二叉树虚拟化为字符串,每个节点值用'!'分割,'#'代表空节点
// 1
// / \
// 2 3
// / \
// 4 5
//序列化为:1!2!4!##5!##3!##
char* Serialize(TreeNode *root)//序列化二叉树(使用前序遍历)
{
string s;
pre_order(root, s);
char *res = new char[s.size() + 1];
memset(res, 0, s.size()+1);
strcpy(res, s.c_str());
return res;
}
TreeNode* Deserialize(char *str) {
if(*str == '#')
return NULL;
int pos = 0;
return build_tree(str, pos);
}
void pre_order(TreeNode *root, string& s)
{
if(root == NULL)
{
s += "#";
return ;
}
else
s = s + to_string(root->val) + "!";
pre_order(root->left, s);
pre_order(root->right, s);
}
TreeNode* build_tree(char *str, int &pos)
{
if(str[pos] == '#')
{
pos++;
return NULL;
}
int x = 0;
for(; str[pos] != '\0' && str[pos] != '!'; pos++)
x = x * 10 + str[pos] - '0';
TreeNode *p = new TreeNode(x);
if(str[pos] == '\0')
return p;
else
pos++;
p->left = build_tree(str, pos);
p->right = build_tree(str, pos);
return p;
}