二叉树
指针实现二叉树
#include<bits/stdc++.h>
using namespace std;
typedef int TElemType;
struct node
{
TElemType data;
node* lchild;
node* rchild;
};
// 二叉树建树前根节点不存在
node* root = NULL;
// 建立节点
node* newNode(int v) // v为节点权值
{
node* Node = new node; // 申请内存
Node->data = v;
Node->lchild = Node->rchild = NULL;
return Node;
}
// 查找值为x的结点并将其值修改为newdata
void search(node* root, int x, int newdata)
{
if(root == NULL) return;
if(root->data == x) root->data = newdata;
search(root->lchild, x, newdata);
search(root->rchild, x, newdata);
}
// 插入结点
void insert(node* &root, int x)
{
if(root == NULL){
root = newNode(x);
return;
}
if(Judge()) insert(root->lchild, x);
else insert(root->rchild, x);
}
// 建树
node* Create(int data[], int n)
{
node* root = NULL;
for(int i = 0; i < n; i++) insert(root, data[i]);
return root;
}
// 先序遍历
void preorder(node* root)
{
if(root == NULL) return;
printf("%d\n", root->data);
preorder(root->lchild);
preorder(root->rchild);
}
// 中序遍历
void inorder(node* root)
{
if(root == NULL) return;
inorder(root->lchild);
printf("%d\n", root->data);
inorder(root->rchild);
}
// 后序遍历
void postorder(node* root)
{
if(root == NULL) return;
postprder(root->lchild);
postorder(root->rchild);
printf("%d\n", root->data);
}
// 层序遍历
void layerorder(node* root)
{
queue<node*> q;
q.push(root);
while(!q.empty){
node* now = q.front();
q.pop();
printf("%d", now->data);
if(now->lchild != MULL) q.push(now->lchild);
if(now->rchild != NUll) q.push(now->rchild);
}
}
// 求二叉树深度
int find_depth(node* root, int depth, int maxn) // 初始时depth为1,maxn为0
{
if(root == NULL && ){
maxn = depth;
depth --;
return;
}
depth ++;
find_depth(root->lchild, depth, maxn);
find_depth(root->rchild, depth, maxn);
return maxn;
}
结构数组模拟二叉树
#include <bits/stdc++.h>
using namespace std;
typedef char TElemType;
const int maxn = 100010;
struct node{
TElemType data;
int lch;
int rch;
}Node[maxn];
int idx = 0;
// 模拟创建结点(静态指定)
int newNode(int v)
{
Node[idx].data = v;
Node[idx].lch = -1;
Node[idx].rch = -1;
return idx ++;
}
// 查找和修改
void search(int root, int x, int newdata)
{
if(root == -1) return;
if(Node[root].data == x) Node[root].data = newdata;
search(Node[root].lch, x, newdata);
search(Node[root].rch, x, newdata);
}
// 插入
void insert(int &root, int x)
{
if(root == -1){
root == newNode(x);
return;
}
if(Judge()) insert(Node[root].lch, x);
else insert(Node[root].rch, x);
}
int Create(int data[], int n)
{
int root = -1;
for(int i = 0; i < n; i ++) insert(root, data[i]);
return root;
}
// 先序遍历
void preorder(int root)
{
if(roor == -1) return;
printf("%d\n",Node[root].data);
preorder(Node[root].lch);
inorder(Node[root].rch);
}
// 中序遍历
void inorder(int root)
{
if(roor == -1) return;
inorder(Node[root].lch);
printf("%d\n",Node[root].data);
inorder(Node[root].rch);
}
// 后序遍历
void postorder(int root)
{
if(roor == -1) return;
postorder(Node[root].lch);
postorder(Node[root].rch);
printf("%d\n",Node[root].data);
}
// 层序遍历
void layeroeder(int root)
{
queue<int> q;
q.push(root);
while(!q.empty()){
int now = q.front();
q.pop();
printf("%d", Node[now].data);
if(Node[now].lch != -1) q.push(Node[now].lch);
if(Node[now].rch != -1) q.push(Node[now].rch);
}
}
二叉树还原
条件:已知中序序列和其他任意遍历序列,还原二叉树
思路:任意序找根,中序分左右,递归求解
方法:双指针法
例:给定一棵二叉树的先序遍历序列和中序遍历序列,重建这棵二叉树。
法一:真的双指针
用string的substr()方法取子串
法二:双指针思想,数组下标作指针
假设已知先序序列为 pre1, pre2, …, pren;
中序序列为in1, in2, …; inn;
- 由先序性质:pre1 是当前二叉树的根结点;
- 由中序性质:根结点将中序序列划分成左子树和右子树
- 因此:在中序序列中找到ink,使 ink == pre1,就找到根结点
- 故:左子树结点个数 numLeft = k - 1;
- 故:左子树先序序列区间为 [2, k],中序序列区间为 [1,k-1];
- 故:右子树先序序列区间为 [k+1, n],中序序列区间为 [k+1, n];
- 只需往左子树和右子树进行递归构建二叉树
- 如果递归过程中,当前先序序列的区间为 [preL, preR],中序序列的区间为 [inL, inR];
- 那么:左子树的结点个数为 numLeft = k - inL;
- 故:左子树先序序列区间为 [pre+1, pre+numLeft],中序序列区间为 [inL, k-1];
- 故:右子树先序序列区间为 [preL+numLeft+1, preR],中序序列区间为 [k+1, inR];
- 且:递归边界为先序序列的长度小于0,此时当前二叉树不存在。
// 当前先序序列区间为[preL, preR], 中序序列区间为[inL, inR] , 返回根结点地址
node* create(int preL, int preR, int inL, int inR)
{
if(preL > preR) return NULL; // 先序序列长度小千等千0时, 直接返回
node* root = new node; // 新建一个新的结点, 用来存放当前二叉树的根结点
root->data = pre[preL]; // 新结点的数据域为根结点的值
int k;
for(k = inL; k <= inR; k++)
if (in[k] == pre[preL]) break; // 在中序序列中找到in[k] == pre[L]的结点
int numLeft = k - inL; // 左子树的结点个数
// 左子树的先序区间为[preL+l, preL+numLeft], 中序区间为[inL, k-1]
// 返回左子树的根结点地址, 赋值给root的左指针
root->lchild = create(preL + 1, preL + numLeft, inL, k - l);
// 右子树的先序区间为(preL + numLeft + 1, preR], 中序区间为[k+l, inR)
// 返回右子树的根结点地址, 赋值给root的右指针
root->rchild = create(preL + numLeft + 1, preR, k + 1, inR);
return root;
}
二叉查找树
树
树的静态实现
动态实现略了,原理一模一样。
双亲表示法:指针域只存双亲地址
struct tree{
typename val;
int par;
};
孩子表示法:指针域只存孩子地址,由于子结点个数无法预知,故使用vector存孩子
struct tree{
typename val;
vector<int> cld ;
};
双亲孩子表示法:指针域既存双亲地址,也存孩子地址
struct tree{
typename val;
int par;
vector<int> cld;
};
孩子兄弟表示法:
不管有多少个孩子,只定义两个指针域,左指针域存长子地址,右指针域存第一个兄弟地址。
优点:将任意个子节点的存储简化为两个指针域的存储。
struct tree{
typename val;
int eld;
int bro;
};