文章目录
二叉树
一、存储结构
1.顺序存储
将二叉树存储在一个数组中,通过下标确定节点位置。(0表示节点不存在)
节点n左孩子为下标2n+1,右孩子下标为2n+2。
n | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|---|
an | 1 | 2 | 3 | 4 | 5 | 0 | 7 |
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4hjyFmS6-1650030876366)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220405192547727.png)]
2.链式存储
将二叉树存储在如下结构中
typedef struct Tree{
Elemtype data;
struct Tree *lchild,*rchild;
}Tree,*T;
二、二叉树的遍历
先序、中序、后序三种遍历的区别仅在访问子树和根节点的顺序。
以下树使用链式结构,栈和队列使用C++ STL。
1.先序遍历:
若空,什么都不做,否则:
1)访问根节点
2)访问左子树
3)访问右子树
void preorder(T t){
if(T!=NULL){
visit(t);
preorder(t->lchild);
preorder(t->rchild);
}
}
非递归算法:
void preorder(T t){
stack<T> s;
T p=t;
while(p||!s.empty()){
if(p){
visit(p);
s.push(p);
p=p->lchild;
}
else {
p=s.top();
s.pop();
p=p->rchild;
}
}
}
2.中序遍历
若空,什么都不做,否则:
1)访问左子树
2)访问根节点
3)访问右子树
void inorder(T t){
if(T!=NULL){
inorder(t->lchild);
visit(t);
inorder(t->rchild);
}
}
非递归算法:
void inorder(T t){
stack<T> s;
T p=t;
while(p||!s.empty()){
if(p){
s.push(p);
p=p->lchild;
}
else {
p=s.top();
s.pop();
visit(p);
p=p->rchild;
}
}
}
3.后序遍历
若空,什么都不做,否则:
1)访问左子树
2)访问右子树
3)访问根节点
void postorder(T t){
if(T!=NULL){
postorder(t->lchild);
postorder(t->rchild);
visit(t);
}
}
非递归算法:
void postorder(T t){
stack<T> s;
T p=t;
while(p||!s.empty()){
if(p){
s.push(p);
p=p->lchild;
}
else {
p=s.top();
s.pop();
p=p->rchild;
visit(p);
}
}
}
4.层次遍历
即一层一层的访问二叉树。
void levelorder(T t){
queue<T> q;
T p;
q.push(t);
while(!q.empty()){
p=q.front();
q.pop();
visit(p);
if(p->lchild)q.push(p->lchild);
if(p->rchild)q.push(p->rchild);
}
}
三、线索二叉树
引入线索二叉树是为了加快查找结点前驱和后继的速度。
其存储结构如下:
typedef struct threadnode{
elemtype data;
struct threadnode *lchild,*rchild;
int ltag,rtag;
}threadnode,*threadtree;
取值 | 意义 | |
---|---|---|
ltag | 0 | lchild指向结点的左孩子 |
ltag | 1 | lchild指向结点的前驱 |
rtag | 0 | rchild指向结点的右孩子 |
rtag | 1 | rchild指向结点的后继 |
通过中序遍历对二叉树线索化:
二叉树的线索化是将二叉链表中的空指针改为指向前驱或后继的线索,而前驱或后继的信息只有在遍历时才能得到,因此线索化的实质就是遍历一次二叉树。
副指针pre指向刚刚访问的结点,初始为空。
void inthread(threadtree &p,threadtree &pre){
if(p!=NULL){
inthread(p->lchild,pre);
if(p->lchild==pre);
p->latg=1;
}
if(pre!=NULL&&pre->rchild==NULL){
pre->rchild=p;
pre->rtag=1;
}
pre=p;
inthread(p->rchild,pre);
}
四、哈夫曼树
1.树的带权路径长度WPL
给树的每一个叶子结点赋予一个权值,WPL=对每个叶子结点到根节点的路径长度×结点权值求和
2.哈夫曼树
WPL最小的二叉树称为哈夫曼树。
五、二叉排序树BST
1.定义
对于一棵二叉排序树树:
若左子树非空,则左子树上所有结点的值小于根节点的值。
若右子树非空,则右子树上所有结点的值大于根节点的值。
左右子树同时是二叉排序树
2.数据结构
typedef struct Tree{
int val;
Tree *left,*right;
}*T;
3.插入操作
void insert(T t,int n){
if(t==NULL){
t=(T)malloc(sizeof(Tree));
t->val=n;
}
else if(t->val > n)insert(t->left,n);
else insert(t->right,n);
}
4.查找操作
int search(T t,int n){
if(t==NULL)return -1;
if(n>t->val)return search(t->right,n);
else return search(t->left,n);
}
5.建树
假设数据存在于长度为n的数组a中。
T build(int a[],int n){
T t;
for(int i=0;i<n;i++){
insert(t,a[i]);
}
return t;
}
){
if(t==NULL)return -1;
if(n>t->val)return search(t->right,n);
else return search(t->left,n);
}
### 5.建树
假设数据存在于长度为n的数组a中。
~~~c
T build(int a[],int n){
T t;
for(int i=0;i<n;i++){
insert(t,a[i]);
}
return t;
}