目录
1.假设根节点是第一层,在二叉树的第i层上最多有2^(n-1)个结点
3.任意一个非空二叉树,度为0的结点数比度为2的结点数多一个
5.具有N个结点的完全二叉树的深度为log2(N+1)(向下取整)或者(log2N)+1(向上取整)
6. 如果有一棵n个结点的完全二叉树,其结点编号按照层次序(从上到下,从左到右),则除根结点外,满足[i/2 , i, 2i, 2i+1]的规则
1.直接采用数组存储二叉树,将任意一个二叉树补成完全二叉树,不过这样容易造成空间上的浪费
二叉树的五种基本形态:
1.二叉树可以是空树

2.只有一个根节点的树

3.斜树:只有左子树或右子树的树

4.左右孩子都有的树

二叉树的性质:
1.假设根节点是第一层,在二叉树的第i层上最多有2^(n-1)个结点
解释:若想要结点数最多,则要求除叶子结点外,每个结点的度都为2
层数 该层结点数
一层: 根节点 1
二层: 1*2 2
三层 2*2 4
四层 4*2 8
n层 2*2*...*2 2^(n-1)
2.深度为k的二叉树,最多有(2^k)-1个结点
将所有层次的结点数相加,再根据等比数列求和公式可得
满二叉树
而有(2^k)-1个结点的树有被称作满二叉树,满二叉树没有度为1的结点
完全二叉树
对满二叉树的结点编号(从上到下再从左到右)从后面删除若干个连续的编号最大的结点,剩下的部分就是完全二叉树
如下图删除15.14.13

同时,对于完全二叉树来说,度为1的结点要么没有,要么只有一个
满二叉树也是完全二叉树
3.任意一个非空二叉树,度为0的结点数比度为2的结点数多一个
解释:
按照度来分,我们可以将其分成度分别为0,1,2的结点:
n = n0 + n1 + n2
按照有无父亲,或者说是是否可以当作孩子结点,我们可以分成根节点和其他结点:
n = 1 + (n-1)
而在这(n-1)个孩子结点里,我们可以再将每个结点看作父亲,
度为0的父亲没有孩子 0 * n0
度为1的父亲一个孩子 1 * n1
度为2的父亲两个孩子 2 * n1
所以可以推出
n = 1 + 0 * n0 + n1 + 2n1
n0 + n1 + n2 = 1 + n1 + 2n1
n0 = n2 + 1
或者从连线个数的角度理解:
n个结点的树有n-1条连线
度为0的树向下有0条
度为1的树向下有n1条
度为2的树向下有2n2条
n1+n2+n0-1 =n1+2n2
n0-1=n2
4.在完全二叉树中有无度为1的判断
没有度为1的结点,n=n0+n2=n2+1+n2=2n2+1
有度为1的结点,n=n0+n1+n2=2n2+2
所以在完全二叉树中,结点数为奇数,没有度为1的结点;结点数为偶数,有度为1的结点且只有1个
5.具有N个结点的完全二叉树的深度为log2(N+1)(向下取整)或者(log2N)+1(向上取整)

6. 如果有一棵n个结点的完全二叉树,其结点编号按照层次序(从上到下,从左到右),则除根结点外,满足[i/2 , i, 2i, 2i+1]的规则
二叉树的存储方式
1.直接采用数组存储二叉树,将任意一个二叉树补成完全二叉树,不过这样容易造成空间上的浪费
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
char data[1005];
int flag;//=0 左 =1右孩子
int find(char fx)
{
for (int i = 1; i < 1005; i++)
{
if (data[i] == fx)
{
return i;
}
}
}
int main()
{
int n;
char root;
printf("读入数据个数:\n");
scanf("%d", &n);
for (int i = 0; i < 1005; i++)
{
data[i] = ' ';
}
getchar();
printf("读入根结点:\n");
scanf("%c", &root);
data[1] = root;
char x, fx;//数据为x,fx为x的父亲
int fxi, xi;
for (int i = 1; i <= n - 1; i++)
{
getchar();
printf("读入剩下的结点(x fx flag):\n");
scanf("%c %c %d", &x, &fx, &flag);
fxi = find(fx);//寻找父亲结点的下标
if (flag == 0)
{
xi = 2 * fxi;
}
else {
xi = 2 * fxi + 1;
}
data[xi] = x;
}
getchar();
printf("查找某个结点的孩子父亲结点:\n");
scanf("%c", &x);
xi = find(x);
if (xi == 1)
{
printf("根节点,无父亲节点\n");
}
else {
printf("父亲结点:%c\n", data[xi / 2]);
}
printf("孩子节点是:%c %c\n", data[2 * xi], data[2 * xi + 1]);
return 0;
}
2.二叉链表存储
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
//二叉链表节点结构
typedef struct BTNode {
char data;
struct BTNode* left;//保存左孩子地址
struct BTNode* right;//保存右孩子地址
//struct BTNode* fa;//保存父亲的地址
}BTNode, * BTree;
BTree initBTree(char root)
{
BTNode* r = (BTNode*)malloc(sizeof(BTNode));
if (r == NULL)
{
printf("空间分配失败\n");
return NULL;
}
r->data = root;
r->left = r->right = NULL;
//r->fa=NULL;
return r;
}
BTNode* find(BTree r, char fx)
{
if (r == NULL || r->data == fx)
{
return r;
}
if (r->left != NULL)
{
BTNode* ans = find(r->left, fx);
if (ans != NULL && ans->data == fx)
{
return ans;
}
}
if (r->right != NULL)
{
BTNode* ans = find(r->right, fx);
if (ans != NULL && ans->data == fx)
{
return ans;
}
}
return NULL;
}
BTree insert(BTree r, char x, char fx, int flag)
{
BTNode* f = find(r, fx);
if (f == NULL)
{
printf("父亲节点不存在,不能插入\n");
}
else
{
BTNode* s = (BTNode*)malloc(sizeof(BTNode));
//判断s==NULL
s->data = x;
s->left = s->right = NULL;
//s->fa=f;
if (flag == 0)
{
f->left = s;
}
else {
f->right = s;
}
}
return r;
}
int main()
{
int n;
int flag;//=0 左 =1右孩子
BTree r = NULL;
char root;
printf("输入结点的总个数:\n");
scanf("%d", &n);
getchar();
printf("输入根节点:\n");
scanf("%c", &root);
r = initBTree(root);
char x, fx;
for (int i = 1; i <= n - 1; i++)
{
getchar();
printf("输入结点信息(x, fx, flag):\n");
scanf("%c %c %d", &x, &fx, &flag);
r = insert(r, x, fx, flag);
}
getchar();
printf("输入要查找的结点:\n");
scanf("%c", &x);
BTNode* p = find(r, x);
if (p != NULL && p->left != NULL)
{
printf("左孩子%c\n", p->left->data);
}
if (p != NULL && p->right != NULL)
{
printf("右孩子%c\n", p->right->data);
}
return 0;
}
针对二叉树的操作
1.二叉树的遍历/搜索
遍历:沿某条搜索路径周游二叉树,对树中的每一个节点访问一次且仅访问一次。
对线性结构而言,只有一条搜索路径(因为每个结点均只有一个后继)
二叉树是非线性结构,每个结点有两个后继,则存在如何遍历即按什么样的搜索路径进行遍历的问题,这里分作按层次(广度)和深度两种
广度
按层次,父子关系,知道了父,那么就把其所有的子结点都看一遍
算法思想
引入队列,将根结点入队
从队列中取出队头元素,访问该结点,将该结点的所有孩子节点入队
再次从队列中取出队头元素,并访问,以此重复
直到队列为空,说明所有元素都遍历完成

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
//链式队列
//队列的单链表节点结构
typedef struct QNode {
char data;//数据
struct QNode* next;
}QNode;
QNode* front;
QNode* rear;
void Initqueue()//初始化队列
{
QNode* q = (QNode*)malloc(sizeof(QNode));
if (q == NULL)
{
printf("队列分配失败\n");
return;
}
front = rear = q;
q->next = NULL;
}
void Enqueue(char x)//入队
{
QNode* s = (QNode*)malloc(sizeof(QNode));
//s判空
s->data = x;
s->next = NULL;
rear->next = s;
rear = s;
}
int IsEmpty()
{
if (front->next == NULL)
{
return 1;//空
}
return 0;//非空
}
char Dequeue()
{
if (IsEmpty() == 0)
{
QNode* q = front->next;
front->next = q->next;
char x = q->data;
if (front->next == NULL)
{
rear = front;
}
free(q);
q = NULL;
return x;
}
else {
printf("队空\n");
char x = ' ';
return x;
}
}
//二叉链表节点结构
typedef struct BTNode {
char data;
struct BTNode* left;//保存左孩子地址
struct BTNode* right;//保存右孩子地址
}BTNode, * BTree;
BTree initBTree(char root)
{
BTNode* r = (BTNode*)malloc(sizeof(BTNode));
if (r == NULL)
{
printf("空间分配失败\n");
return NULL;
}
r->data = root;
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* ans = find(r->left, fx);
if (ans != NULL && ans->data == fx)
{
return ans;
}
}
if (r->right != NULL)
{
BTNode* ans = find(r->right, fx);
if (ans != NULL && ans->data == fx)
{
return ans;
}
}
return NULL;
}
BTree insert(BTree r, char x, char fx, int flag)
{
BTNode* f = find(r, fx);
if (f == NULL)
{
printf("父亲节点不存在,不能插入\n");
}
else
{
BTNode* s = (BTNode*)malloc(sizeof(BTNode));
//判断s==NULL
s->data = x;
s->left = s->right = NULL;
if (flag == 0)
{
f->left = s;
}
else {
f->right = s;
}
}
return r;
}
void visit(char x)
{
printf("%c ", x);
}
void LevelOrder(BTree r)//层次遍历
{
Initqueue();//初始化队列
if (r == NULL)
{
printf("空树,无法遍历\n");
return;
}
Enqueue(r->data);//根节点数据入队
char x;
BTNode* q = NULL;
while (IsEmpty() == 0)
{
x = Dequeue();
visit(x); //访问节点
q = find(r, x);//找x所在的节点q
if (q->left != NULL)
{
Enqueue(q->left->data);
}
if (q->right != NULL)
{
Enqueue(q->right->data);
}
}
printf("\n");
}
int main()
{
int n;
int flag;//=0 左 =1右孩子
BTree r = NULL;
char root;
scanf("%d", &n);
getchar();
scanf("%c", &root);
r = initBTree(root);
char x, fx;
for (int i = 1; i <= n - 1; i++)
{
getchar();
scanf("%c %c %d", &x, &fx, &flag);
r = insert(r, x, fx, flag);
}
LevelOrder(r);
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
*/
这里还需要注意队列存储的数据,如果是值,那么队列类型就是值的类型;如果是结点,那么队列类型就是整个结构体类型
深度
按深度,一条道走到黑,然后再返回走另一条道
深度有三种:先序、中序、后序
先序:根左右
中序:左根右
后序:左右根
采用递归
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
//链式队列
//队列的单链表节点结构
typedef struct QNode {
char data;//数据
struct QNode* next;
}QNode;
QNode* front;
QNode* rear;
int IsEmpty()
{
if (front->next == NULL)
{
return 1;//空
}
return 0;//非空
}
//二叉链表节点结构
typedef struct BTNode {
char data;
struct BTNode* left;//保存左孩子地址
struct BTNode* right;//保存右孩子地址
}BTNode, * BTree;
BTree initBTree(char root)
{
BTNode* r = (BTNode*)malloc(sizeof(BTNode));
if (r == NULL)
{
printf("空间分配失败\n");
return NULL;
}
r->data = root;
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* ans = find(r->left, fx);
if (ans != NULL && ans->data == fx)
{
return ans;
}
}
if (r->right != NULL)
{
BTNode* ans = find(r->right, fx);
if (ans != NULL && ans->data == fx)
{
return ans;
}
}
return NULL;
}
BTree insert(BTree r, char x, char fx, int flag)
{
BTNode* f = find(r, fx);
if (f == NULL)
{
printf("父亲节点不存在,不能插入\n");
}
else
{
BTNode* s = (BTNode*)malloc(sizeof(BTNode));
//判断s==NULL
s->data = x;
s->left = s->right = NULL;
if (flag == 0)
{
f->left = s;
}
else {
f->right = s;
}
}
return r;
}
void visit(char x)
{
printf("%c ", x);
}
//对以r为根的树进行先序遍历
void PerOrder(BTree r)//先序遍历
{
if (r == NULL)//空树不需要遍历
{
return;
}
visit(r->data);//访问根节点
PerOrder(r->left);//对左子树进行先序遍历
PerOrder(r->right);//对右子树进行先序遍历
}
//对以r为根的树进行中序遍历
void InOrder(BTree r)//中序遍历
{
if (r == NULL)//空树不需要遍历
{
return;
}
InOrder(r->left);//对左子树进行中序遍历
visit(r->data);//访问根节点
InOrder(r->right);//对右子树进行中序遍历
}
//对以r为根的树进行后序遍历
void PostOrder(BTree r)//后序遍历
{
if (r == NULL)//空树不需要遍历
{
return;
}
PostOrder(r->left);//对左子树进行后序遍历
PostOrder(r->right);//对右子树进行后序遍历
visit(r->data);//访问根节点
}
int main()
{
int n;
int flag;//=0 左 =1右孩子
BTree r = NULL;
char root;
scanf("%d", &n);
getchar();
scanf("%c", &root);
r = initBTree(root);
char x, fx;
for (int i = 1; i <= n - 1; i++)
{
getchar();
scanf("%c %c %d", &x, &fx, &flag);
r = insert(r, x, fx, flag);
}
//先序遍历
PerOrder(r);
//中序遍历s
InOrder(r);
//后序遍历
PostOrder(r);
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
*/
采用栈
#define _CRT_SECURE_NO_WARNINGS
#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 右孩子
//---------------------链栈----------------------
//单链表的节点结构:将整个节点入队
typedef struct stackNode {
struct BTNode* data;
struct stackNode* next;
}sstack;
//初始化链栈
sstack* initstack()
{
sstack* s = (sstack*)malloc(sizeof(sstack));
if (s == NULL)
{
printf("栈空间分配失败\n");
return NULL;
}
s->next = NULL;
return s;
}
//入栈
void ppush(sstack* s, BTNode* k)
{//头插
sstack* p = (sstack*)malloc(sizeof(sstack));
p->data = k;
p->next = s->next;
s->next = p;
}
//判空
int empty(sstack* s)
{
if (s->next == NULL)
{
return 1;//栈空
}
return 0;//栈非空
}
//出栈:返回栈顶元素,将其在栈中删除
BTNode* ppop(sstack* s)
{
if (empty(s) == 1)
{
printf("栈空\n");
return NULL;
}
sstack* p = s->next;
BTNode* k = p->data;
s->next = p->next;
free(p);
p = NULL;
return k;
}
//得到栈顶元素,但不出栈
BTNode* gett(sstack* s)
{
if (empty(s) == 1)
{
printf("栈空\n");
return NULL;
}
BTNode* k = s->next->data;
return k;
}
//-----------------------------------------------------------------
//建树
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)
{//递归
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;
}
}
}
//--------------遍历------------------
void visit(BTNode* p)
{
printf("%c ", p->data);
}
//先序
void PreOrder(BTree ro)
{
sstack* s = initstack();
if (ro == NULL)
{
printf("空树,不需要遍历\n");
return;
}
BTNode* p = ro;//p辅助遍历
BTNode* k = NULL;
while (p != NULL || empty(s) == 0)
{
if (p != NULL)
{
visit(p);
ppush(s, p);
p = p->left;
}
else
{
k = ppop(s);
p = k->right;
}
}
}
//中序
void InOrder(BTree ro)
{
sstack* s = initstack();
if (ro == NULL)
{
printf("空树,不需要遍历\n");
return;
}
BTNode* p = ro;//p辅助遍历
BTNode* k = NULL;
while (p != NULL || empty(s) == 0)
{
if (p != NULL)
{
ppush(s, p);
p = p->left;
}
else
{
k = ppop(s);
visit(k);
p = k->right;
}
}
}
//后序
void PostOrder(BTree ro)
{
sstack* s = initstack();
if (ro == NULL)
{
printf("空树,不需要遍历\n");
return;
}
BTNode* p = ro;//p辅助遍历
BTNode* pre = NULL;//pre在遍历过程中保存刚刚访问过的节点
BTNode* k = NULL;
while (p != NULL || empty(s) == 0)
{
if (p != NULL)
{
ppush(s, p);
p = p->left;
}
else
{
k = gett(s);
if (k->right != NULL && pre != k->right)//右孩子存在且没访问
{
p = k->right;//访问右孩子
}
else
{
k = ppop(s);
visit(k);
pre = k;
}
}
}
}
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);
}
PostOrder(ro);
return 0;
}

9106

被折叠的 条评论
为什么被折叠?



