1.二叉树的概念
⼆叉树是每个结点最多有两个⼦树的树结构。也就是说⼆叉树不允许存在度⼤于2的树。它有五种最基本的形态:⼆叉树可以是空集。根可以有空的左⼦树或者右⼦树;或者左右⼦树都是空。其中只有 左⼦树或者右子树的叫做斜树。
为何要重点研究每结点最多只有两个“叉” 的树?
二叉树的结构最简单,规律性最强;
可以证明,所有树都能转为唯一对应的二叉树,不失一般性。
普通树(多叉树)若不转化为二叉树,则运算很难实现。
2.二叉树的性质
3.几个特殊的二叉树
1.满二叉树
一棵深度为k且有2^k-1个结点的二叉树。叶子只能出现在最后⼀层,内部结点的度都为2,如图所示。
特点:1.叶子只能出现在最下一层 2.只有度为0和度为2的结点 3.在同样深度的二叉树中叶子结点(结点)个数最多
2.完全二叉树
深度为k的,有n个结点的二叉树,当且仅当其每一个 结点都与深度为k 的满二叉树中编号从1至n的结点一 一对应。只有最后一层叶子不满,且 叶子全部集中在左边,如图所示。
特点:1.叶子结点只能出现在最下两层,且最下层的叶子结点都集中在二叉树的左部; 2.完全二叉树中如果有度为1的结点,只可能有一个,且该结点只有左孩子。 3.深度为k的完全二叉树在k-1层上 一定是满二叉树。满二叉树也是完全二叉树,而完全二叉树不一定是满二叉树。
3.二叉排序树
左子树上所有结点的关键字均小于根结点的关键字;右子树上的所有结点的关键字均大于根结点的关键字;左子树和右子树又各是一棵二叉排序树。
4.平衡二叉树
树上任一结点的左子树和右子树的深度之差不超过1。
后面的两棵树我会在下一个复习笔记中详细介绍。
4.树的存储结构
1.顺序存储
实现:按满二叉树的结点层次编号,依次存放二叉树中的数据元素(由性质5,标号存在特征)
特点: 点间关系蕴含在其存储位置中浪费空间(尤其是斜树最为明显),适于存满二叉树和完全二叉树
代码实现:
#include <stdlib.h>
#include <stdio.h>
# include <string.h>
char data[1005];
int size;
int flag;//=0 左孩子, =1 右孩子
int find(char fx)//查找fx的下标
{
for(int i=1;i<=size;i++)
{
if(data[i]==fx)
{
return i;
}
}
return -1;
}
int main()
{
int n,fx_i,x_i;
char x,fx;
scanf("%d",&n);
for(int i=0;i<=n;i++)
{//初始化为' ';空格
data[i]=' ';
}
getchar();
scanf("%c",&x);
data[1]=x;
size=1;
for(int i=2;i<=n;i++)
{
getchar();
scanf("%c %c %d",&x,&fx,&flag);
fx_i=find(fx);
if(fx_i!=-1)
{
if(flag==0)
{
x_i=fx_i*2;
}
else{
x_i=fx_i*2+1;
}
data[x_i]=x;
size++;
}
}
getchar();
scanf("%c",&x);
x_i=find(x);
printf("孩子节点:%c %c\n",data[2*x_i],data[2*x_i+1]);
return 0;
}
2.链式存储
由于⼆叉树的每个结点最多只能有两个⼦树,因此我们就不需要使⽤上述的3种表达法来做。可以直接设置⼀个结点具有两个指针域与⼀个数据域,那么这样就可以建好⼆叉树链表。
代码实现:
#include <stdlib.h>
#include <stdio.h>
# include <string.h>
typedef struct BTNode{
char data;
struct BTNode* left;
struct BTNode* right;
//父亲指针
}BTNode,*BTree;
int flag;//=0 左孩子, =1 右孩子
BTree initTree(char x)
{
BTNode* r=(BTNode*)malloc(sizeof(BTNode));
if(r==NULL)
{
printf("分配失败\n");
return NULL;
}
else{
r->data=x;
r->left = r->right=NULL;
return r;
}
}
BTNode* find(BTree ro,char fx)//查找fx所在的节点
{//递归
if(ro==NULL||ro->data==fx)
{
return ro;
}
if(ro->left!=NULL)
{
BTNode* f=find(ro->left ,fx);
if(f!=NULL&&f->data==fx)
{
return f;
}
}
if(ro->right !=NULL)
{
BTNode* f=find(ro->right ,fx);
if(f!=NULL&&f->data==fx)
{
return f;
}
}
return NULL;
}
void insert(BTree ro,char x,char fx,int flag)
{
BTNode* f=find(ro,fx);
if(f!=NULL)
{
BTNode* s=(BTNode*)malloc(sizeof(BTNode));
s->data=x;
s->left=s->right=NULL;
if(flag==0)
{
f->left=s;
}
else{
f->right=s;
}
}
}
int main()
{
int n;
char x,fx;
BTree ro=NULL;
scanf("%d",&n);
getchar();
scanf("%c",&x);
ro=initTree(x);
for(int i=2;i<=n;i++)
{
getchar();
scanf("%c %c %d",&x,&fx,&flag);
insert(ro,x,fx,flag);
}
getchar();
scanf("%c",&x);
BTNode* p=find(ro,x);
if(p!=NULL)
{
if(p->left!=NULL)
{
printf("左%c\n",p->left->data );
}
if(p->right !=NULL)
{
printf("右%c\n",p->right ->data );
}
}
return 0;
}
5.遍历二叉树
1.概念
遍历定义:指以一定的次序访问二叉树中的每个结点,并且每个 结点仅被访问一次。
“访问”的含义:输出结点的信息
遍历用途:是树结构插入、删除、修改、查找和排序运算的前提 ,是二叉树一切运算的基础和核心。
一次完整的遍历可产生树中结点的一个线性序列。
2.遍历规则
二叉树由根、左子树、右子树构成
D、L、R的组合定义了六种可能的遍历方案: LDR, LRD, DLR, DRL, RDL, RLD
若限定先左后右,则有三种实现方案: DLR先序遍历 LDR中序遍历 LRD后序遍历
3.遍历代码展示
首先,不管是先序,中序,后序都属于深度遍历,有递归版本和非递归版本(运用栈)
1.递归版本
#include <iostream>
using namespace std;
typedef struct BTNode
{
char data;
struct BTNode* left;
struct BTNode* right;
}BTNode, *Btree;
Btree initTree(char x)
{
BTNode *r = new BTNode;
if (r == NULL)
{
cout << "defate!" << endl;
return NULL;
}
else
{
r->data = x;
r->left = r->right = NULL;
return r;
}
}
BTNode *find(Btree r, char fx)
{
if (r == NULL || r->data == fx)
{
return r;
}
if (r->left != NULL)
{
BTNode * f = find(r->left, fx);
if (f != NULL && f->data == fx)
{
return f;
}
}
if (r->right != NULL)
{
BTNode * f = find(r->right, fx);
if (f != NULL && f->data == fx)
{
return f;
}
}
return NULL;
}
void insert(BTNode * r, char x, char fx, int flag)
{
BTNode * f = find(r, fx);
if (f != NULL)
{
BTNode *s = new BTNode;
s->data = x;
s->left = s->right = NULL;
if (flag == 0)
{
f->left = s;
}
else
{
f->right = s;
}
}
}
//递归调用
void preOrder(Btree r)
{
if (r == NULL)
{
return;
}
cout << r->data << " ";
if (r->left != NULL)
{
preOrder(r->left);
}
if (r->right!= NULL)
{
preOrder(r->right);
}
}
void inOrder(Btree r)
{
if (r == NULL)
{
return;
}
if (r->left != NULL)
{
inOrder(r->left);
}
cout << r->data << " ";
if (r->right != NULL)
{
inOrder(r->right);
}
}
int main()
{
int n;
char x, fx;
int flag;
cin >> n >> x;
Btree root = initTree(x);
for (int i = 2; i <= n; i++)
{
//getchar();
cin >> x >> fx >> flag;
insert(root, x, fx, flag);
}
cout << endl << "read" << endl;
cin >> x;
BTNode * p = find(root, x);
if (p != NULL && p->left != NULL)
{
cout << p->left->data << endl;
}
else
{
cout << "defate" << endl;
}
//深度遍历:①先序遍历
//preOrder(root);
//②中序遍历
//inOrder(root);
//③后序遍历
//befOrder(root);
return 0;
}
2.非递归版本
#include <iostream>
using namespace std;
//运用栈
//树的结点结构
typedef struct BTNode
{
char data;
struct BTNode* left;
struct BTNode* right;
}BTNode, *Btree;
//栈的结点结构
typedef struct stackNode
{
BTNode * data;
struct stackNode * next;//结构体内变量想要初始化结构体本身需要加struct
}sstack;
sstack * s = NULL;//声明一个栈
void stack_init()
{
s = new sstack;
if (s == NULL)
{
cout << "defate" << endl;
return;
}
s->next = NULL;
return;
}
//入栈
void push_stack(BTNode * k)
{
//头插
sstack * p = new sstack;
p->data = k;
p->next = s->next;
s->next = p;
}
//判空
bool empty()
{
if (s->next == NULL)
{
return true;
}
return false;
}
//出栈
BTNode * popp()
{
if (empty() == true)
{
cout << "栈空!" << endl;
return NULL;
}
sstack * p = s->next;
BTNode * k = p->data;
s->next = p->next;
delete p;
p = NULL;
return k;
}
//得到栈顶元素
BTNode * Get()
{
if (empty() == true)
{
cout << "栈空!" << endl;
return NULL;
}
return s->next->data;
}
Btree initTree(char x)
{
BTNode *r = new BTNode;
if (r == NULL)
{
cout << "defate!" << endl;
return NULL;
}
else
{
r->data = x;
r->left = r->right = NULL;
return r;
}
}
BTNode *find(Btree r, char fx)
{
if (r == NULL || r->data == fx)
{
return r;
}
if (r->left != NULL)
{
BTNode * f = find(r->left, fx);
if (f != NULL && f->data == fx)
{
return f;
}
}
if (r->right != NULL)
{
BTNode * f = find(r->right, fx);
if (f != NULL && f->data == fx)
{
return f;
}
}
return NULL;
}
void insert(BTNode * r, char x, char fx, int flag)
{
BTNode * f = find(r, fx);
if (f != NULL)
{
BTNode *s = new BTNode;
s->data = x;
s->left = s->right = NULL;
if (flag == 0)
{
f->left = s;
}
else
{
f->right = s;
}
}
}
//非递归调用
//1、先序遍历
void preOrder(Btree ro)
{
if (ro == NULL)
{
cout << "树为空!" << endl;
return;
}
stack_init();
//根结点入栈
push_stack(ro);
while (empty() == false)
{
BTNode * k = popp();
cout << k->data << " ";
if (k->right != NULL)
{
push_stack(k->right);
}
if (k->left != NULL)
{
push_stack(k->left);
}
}
return;
}
//2、中序遍历
void inOrder(Btree ro)
{
if (ro == NULL)
{
cout << "树空!" << endl;
return;
}
stack_init();
BTNode * n = ro;
BTNode * k = NULL;
while (n != NULL || empty() == false)
{
if (n != NULL)
{
push_stack(n);
n = n->left;
}
else
{
k = popp();
cout << k->data << " ";
n = k->right;//用n遍历k的右孩子
}
}
return;
}
//3、后序遍历
void postOrder(Btree ro)
{
if (ro == NULL)
{
cout << "树空!" << endl;
return;
}
stack_init();
BTNode * n = ro;
BTNode * k = NULL;
BTNode * pre = NULL;
while (n != NULL || empty() == false)
{
if (n != NULL)
{
push_stack(n);
n = n->left;
}
else
{
k = Get();
if (k->right != NULL && pre != k->right)
{
n = k->right;//让n遍历右子树(孩子)
}
else
{
k = popp();
cout << k->data << " ";
pre = k;
n = NULL;//**********让n从右孩子转移到该子树左孩子尽头
}
}
}
return;
}
int main()
{
int n;
char x, fx;
int flag;
cin >> n >> x;
Btree root = initTree(x);
for (int i = 2; i <= n; i++)
{
//getchar();
cin >> x >> fx >> flag;
insert(root, x, fx, flag);
}
cout << endl << "read" << endl;
cin >> x;
BTNode * p = find(root, x);
if (p != NULL && p->left != NULL)
{
cout << p->left->data << endl;
}
else
{
cout << "defate" << endl;
}
//深度遍历:①先序遍历
//preOrder(root);
//②中序遍历
//inOrder(root);
//③后序遍历
postOrder(root);
return 0;
}
/*
9 A
B A 0
E A 1
C B 1
D C 0
F E 1
G F 0
H G 0
K G 1
*/
3.层次遍历(广度遍历)
运用队列的存储
#include <iostream>
using namespace std;
//队列代码->链式
typedef struct qnode
{
char data;
struct qnode* next;
}qnode,*lqueue;
lqueue front, rear;//队头指针和队尾指针
void initqueue()
{
qnode * q = new qnode;
if (q == NULL)
{
cout << "defate!" << endl;
return;
}
front = rear = q;
front->next = NULL;
}
void enqueue(char x)
{
qnode * s = new qnode;
s->data = x;
s->next = NULL;
rear->next = s;
rear = s;
}//尾插
int empty()
{
if (front->next == NULL)
{
return 1;//空
}
return 0;//非空
}
char dequeue()
{
if (empty() == 0)
{
qnode * q = front->next;
front->next = q->next;
char x = q->data;
if (front->next == NULL)
{
rear = front;
}
delete q;
q = NULL;
return x;
}
else
{
cout << "队空" << endl;
}
}
///
//二叉链表的结点结构
typedef struct BTNode
{
char data;
struct BTNode* left;
struct BTNode* right;
}BTNode, *Btree;
Btree initTree(char x)
{
BTNode *r = new BTNode;
if (r == NULL)
{
cout << "defate!" << endl;
return NULL;
}
else
{
r->data = x;
r->left = r->right = NULL;
return r;
}
}
BTNode *find(Btree r, char fx)
{
if (r == NULL || r->data == fx)
{
return r;
}
if (r->left != NULL)
{
BTNode * f = find(r->left, fx);
if (f != NULL && f->data == fx)
{
return f;
}
}
if (r->right != NULL)
{
BTNode * f = find(r->right, fx);
if (f != NULL && f->data == fx)
{
return f;
}
}
return NULL;
}
void insert(BTNode * r, char x, char fx, int flag)
{
BTNode * f = find(r, fx);
if (f != NULL)
{
BTNode *s = new BTNode;
s->data = x;
s->left = s->right = NULL;
if (flag == 0)
{
f->left = s;
}
else
{
f->right = s;
}
}
}
void levelOderBtree(Btree r)
{
//初始化队列
initqueue();
//判断空树
if (r == NULL)
{
cout << "空树" << endl;
return;
}
enqueue(r->data);
char x;
BTNode * q = NULL;
while (empty() == 0)
{
x = dequeue();
cout << x << " ";
q = find(r, x);
if (q->left != NULL)
{
enqueue(q->left->data);
}
if (q->right != NULL)
{
enqueue(q->right->data);
}
}
}
int main()
{
int n;
char x, fx;
int flag;
cin >> n >> x;
Btree root = initTree(x);
for (int i = 2; i <= n; i++)
{
cin >> x >> fx >> flag;
insert(root, x, fx, flag);
}
cout << endl << "read" << endl;
cin >> x;
BTNode * p = find(root, x);
if (p != NULL && p->left != NULL)
{
cout << p->left->data << endl;;
}
//层次遍历
levelOderBtree(root);
return 0;
}