数据结构复习(五)——树和二叉树
一、二叉树
1. 二叉树的顺序存储
#include<stdio.h>
#define MaxSize 10
struct TreeNode
{ElemType value; //结点中的数据元素bool isEmpty; //结点是否为空
};//定义一个长度为MaxSize的数组t,按照从上到下、
//从左到右的顺序依次存储完全二叉树中的各个结点
TreeNode t[MaxSize];//二叉树顺序存储,根节点从1开始编号
//i的左孩子---2i
//i的右孩子---2i+1
//i的父节点---i/2向下取整//初始化时所有结点标记为空
for(int i=0;i<MaxSize;i++)
{t[i].isEmpty=true;
}
2. 二叉树的链式存储
//二叉树的结点(链式存储)--二叉链表
struct ElemType
{int value;
};typedef struct BiTNode
{ELemType data; //数据域struct BiTNode *lchild, *rchild; //左右孩子指针
} BiTNode, *BiTree;//n个结点的二叉链表共有n+1个空链域
//n个结点,一共有2n个指针,
//除了根结点,每个结点的头上都有一个天线,共有n-1个指针非空
//2n-(n-1)==n+1个空链域//定义一颗空树
BiTree root = NULL;//插入根结点1
root = (BiTree)malloc(sizeof(BiTNode));
root->data = {1};
root->lchild = NULL;
root->rchild = NULL;//插入新结点2
BiTNode *p2 = (BiTNode *)malloc(sizeof(BiTNode));
p2->data = {2};
p2->lchild = NULL;
p2->rchild = NULL;
root->lchild = p2; //作为根节点1的左孩子//插入新结点3
BiTNode *p3 = (BiTNode *)malloc(sizeof(BiTNode));
p3->data = {3};
p3->lchild = NULL;
p3->rchild = NULL;
root->rchild = p3; //作为根节点1的右孩子//插入新结点4
BiTNode *p4 = (BiTNode *)malloc(sizeof(BiTNode));
p4->data = {4};
p4->lchild = NULL;
p4->rchild = NULL;
p2->rchild = p4; //作为节点2的右孩子//插入新结点6
BiTNode *p6 = (BiTNode *)malloc(sizeof(BiTNode));
p6->data = {6};
p6->lchild = NULL;
p6->rchild = NULL;
p3->lchild = p6; //作为节点3的左孩子//插入新结点7
BiTNode *p7 = (BiTNode *)malloc(sizeof(BiTNode));
p7->data = {7};
p7->lchild = NULL;
p7->rchild = NULL;
p3->rchild = p7; //作为节点3的右孩子//插入新结点11
BiTNode *p11 = (BiTNode *)malloc(sizeof(BiTNode));
p11->data = {11};
p11->lchild = NULL;
p11->rchild = NULL;
p4->rchild = p11 //作为节点4的右孩子//插入新结点12
BiTNode *p12 = (BiTNode *)malloc(sizeof(BiTNode));
p12->data = {12};
p12->lchild = NULL;
p12->rchild = NULL;
p6->lchild = p12; //作为节点6的左孩子
3. 二叉树的链式存储——三叉链表
//二叉树的结点(链式存储)--二叉链表
struct ElemType
{int value;
};
//二叉树的结点(链式存储)--三叉链表
typedef struct BiTNode
{ELemType data; //数据域struct BiTNode *lchild,*rchild; //左右孩子指针struct BiTNode *parent; //父结点指针
}BiTNode,*BiTree;//定义一颗空树
BiTree root = NULL;//插入根结点1
root = (BiTree)malloc(sizeof(BiTNode));
root->data={1};
root->lchild=NULL;
root->rchild=NULL;//插入新结点2
BiTNode *p2 = (BiTNode *)malloc(sizeof(BiTNode));
p2->data={2};
p2->lchild=NULL;
p2->rchild=NULL;
root->lchild=p2; //作为根节点1的左孩子//插入新结点3
BiTNode *p3 = (BiTNode *)malloc(sizeof(BiTNode));
p3->data={3};
p3->lchild=NULL;
p3->rchild=NULL;
root->rchild=p3; //作为根节点1的右孩子//插入新结点4
BiTNode *p4 = (BiTNode *)malloc(sizeof(BiTNode));
p4->data={4};
p4->lchild=NULL;
p4->rchild=NULL;
p2->rchild=p4; //作为节点2的右孩子//插入新结点6
BiTNode *p6 = (BiTNode *)malloc(sizeof(BiTNode));
p6->data={6};
p6->lchild=NULL;
p6->rchild=NULL;
p3->lchild=p6; //作为节点3的左孩子//插入新结点7
BiTNode *p7 = (BiTNode *)malloc(sizeof(BiTNode));
p7->data={7};
p7->lchild=NULL;
p7->rchild=NULL;
p3->rchild=p7; //作为节点3的右孩子//插入新结点11
BiTNode *p11 = (BiTNode *)malloc(sizeof(BiTNode));
p11->data={11};
p11->lchild=NULL;
p11->rchild=NULL;
p4->rchild=p11 //作为节点4的右孩子//插入新结点12
BiTNode *p12 = (BiTNode *)malloc(sizeof(BiTNode));
p12->data={12};
p12->lchild=NULL;
p12->rchild=NULL;
p6->lchild=p12; //作为节点6的左孩子
4. 二叉树的遍历
typedef struct BiTNode
{int data;struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;//访问节点
void visit(BiTNode *)
{printf("%d\t",T->data);
}//先序遍历(根左右)
void PreOrder(BiTree T)
{if(T!=NULL){visit(T); //访问根节点PreOrder(T->lchild); //递归遍历左子树PreOrder(T->rchild); //递归遍历右子树}
}//中序遍历(左根右)
void InOrder(BiTree T)
{if(T!=NULL){InOrder(T->lchild); //递归遍历左子树visit(T); //访问根节点InOrder(T->rchild); //递归遍历右子树}
}//后序遍历(左右根)
void PostOrder(BiTree T)
{if(T!=NULL){PostOrder(T->lchild); //递归遍历左子树PostOrder(T->rchild); //递归遍历右子树visit(T); //访问根节点}
}
5. 求树的深度
//求树的深度
int treeDepth(BiTree T)
{if(T==NULL){return 0;} else{int l=treeDepth(T->lchild);int r=treeDepth(T->rchild);//数的深度=Max(左子树深度,右子树深度)+1return l>r? l+1: r+1;}
}
6. 二叉树的层次遍历
算法思想:
①初始化一个辅助队列
②根节点入队
③若队列非空,则队头节点入队,访问该结点,并将其左右孩子插入队尾(如果有的话)
④重复③直至队列为空
//二叉树的结点(链式存储)
typedef struct BiTNode
{char data;struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;//链式队列结点
typedef struct LinkNode
{BiTNode *data;struct LinkNode *next;
}LinkNode;typedef struct
{LinkNode *front,*rear; //队头队尾指针
}LinkQueue;//层序遍历
void LevelOrder(BiTree T)
{LinkQueue Q;InitQueue(Q); //初始化辅助队列BiTree p; EnQueue(Q,T); //根结点入队while(isEmpty(Q)!=true) //队列不空则循环{DeQueue(Q,p); //队头节点出队visit(p); //访问出队结点if(p->lchild!=NULL)EnQueue(Q,p->lchild); //左孩子入队if(p->rchild!=NULL)EnQueue(Q,p->rchild); //右孩子入队}
}
二、线索二叉树
1. 存储和遍历算法
//二叉树的结点(链式存储)
typedef struct BiTNode
{ElemType data;struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;//线索二叉树结点(链式存储)
typedef struct ThreadNode
{ElemType data;struct ThreadNode *lchild,*rchild;int ltag,rtag; //左、右线索标志//tag==0,指针指向孩子//tag==1,指针指向"线索"
}//中序遍历
void InOrder(BiTree T) //改名findPre
{if(T!=NULL){InOrder(T->lchild); //递归遍历左子树visit(T); //访问根节点InOrder(T->rchild); //递归遍历右子树}
}//访问结点
void visit(BiTNode *q)
{if(q==p) //当前访问结点刚好是结点pfinal = pre; //找到p的前驱elsepre=q; //pre指向当前访问的节点
}//辅助全局变量,用于查找结点p的前驱
BiTNode *p; //p指向目标结点
BiTNode *pre = NULL; //指向当前访问结点的中序索引前驱
BiTNode *final = NULL; //用于记录最终结果
2. 中序线索化二叉树
//线索二叉树结点
typedef struct ThreadNode
{char data;struct ThreadNode *lchild,*rchild;int ltag,rtag; //左、右线索标志
}ThreadNode,*ThreadTree;//全局遍历pre,指向当前访问结点的前驱
ThreadNode *pre = NULL;//中序线索化二叉树T
void CreatInThread(ThreadTree T)
{pre = NULL; //pre初始为NULLif(T!=NULL) //非空二叉树才能线索化{InThread(T); //中序线索化二叉树Tif(pre->rchild==NULL)pre->rtag=1; //处理遍历的最后一个结点}
}//中序遍历二叉树,一边遍历一边线索化
void InThread(ThreadTree T)
{if(T!=NULL){InThread(T->lchild); //中序遍历左子树visit(T); //访问根节点InThread(T->rchild); //中序遍历右子树}
}void visit(ThreadNode *q)
{if(q->lchild==NULL) //左子树为空,建立前驱线索{q->lchild=pre;q->ltag=1;}if(pre!=NULL && pre->rchild==NULL){pre->rchild=q; //建立前驱结点的后继线索pre->rtag=1; }pre=q;
}
3. 先序线索化二叉树
#include<stdio.h>
//线索二叉树结点
typedef struct ThreadNode
{char data;struct ThreadNode *lchild,*rchild;int ltag,rtag; //左右线索标志
}ThreadNode,*ThreadTree;//全局变量pre,指向当前访问结点的前驱
ThreadNode *pre = NULL;//先序线索化二叉树T
void CreatPreThread(ThreadTree T)
{pre = NULL; //pre初始化为NULLif(T!=NULL) //非空二叉树才能线索化{PreThread(T); //先序线索化二叉树if(pre->rchild==NULL)pre->rtag=1; //处理遍历后的最后一个结点}
}//先序遍历二叉树,一边遍历一边线索化
void PreThread(ThreadTree T)
{if(T!=NULL){visit(T); //先处理根节点if(T->ltag==0) //lchild不是前驱线索时才线索化PreThread(T->lchild); //先序遍历左子树PreThread(T->rchild); //先序遍历右子树}
}void visit(ThreadNode *q) //访问结点
{if(q->lchild==NULL) //左子树为空,建立前驱线索{q->lchild=pre;q->ltag=1;}if(pre!=NULL && pre->rchild==NULL){pre->rchild=q; //建立前驱结点的后继线索pre->rtag=1;}pre=q;
}
4. 后续线索化二叉树
#include<stdio.h>
//线索二叉树结点
typedef struct ThreadNode
{char data;struct ThreadNode *lchild,*rchild;int ltag,rtag; //左右线索标志
}ThreadNode,*ThreadTree;//全局变量pre,指向当前访问结点的前驱
ThreadNode *pre = NULL;//后序线索化二叉树T
void CreatPosthread(ThreadTree T)
{pre = NULL; //pre初始化为NULLif(T!=NULL) //非空二叉树才能线索化{PostThread(T); //后序线索化二叉树if(pre->rchild==NULL)pre->rtag=1; //处理遍历后的最后一个结点}
}//后序遍历二叉树,一边遍历一边线索化
void PostThread(ThreadTree T)
{if(T!=NULL){PreThread(T->lchild); //后序遍历左子树PreThread(T->rchild); //后序遍历右子树visit(T); //访问根节点}
}void visit(ThreadNode *q) //访问结点
{if(q->lchild==NULL) //左子树为空,建立前驱线索{q->lchild=pre;q->ltag=1;}if(pre!=NULL && pre->rchild==NULL){pre->rchild=q; //建立前驱结点的后继线索pre->rtag=1;}pre=q;
}
5. 中序线索二叉树找中序后继
#include<stdio.h>
//线索二叉树结点
typedef struct ThreadNode
{char data;struct ThreadNode *lchild,*rchild;int ltag,rtag; //左右线索标志
}ThreadNode,*ThreadTree;//找到以P为根的子树中,第一个被中序遍历的结点
ThreadNode *FirstNode(ThreadNode *p)
{//循环找到最左下结点(不一定是叶节点)while(p->ltag==0)p=p->rchild;return p;
}//在中序线索二叉树中找到结点P的后继结点
ThreadNode *NextNode(ThreadNode *p)
{//右子树中最左下结点if(p->rtag==0)return FirstNode(p->rchild);elsereturn p->rchild; //rtag==1直接返回后继线索
}//对中序线索二叉树进行中序遍历(利用线索实现的非递归算法)
void InOrder(ThreadNode *T)
{for(ThreadNode *p = FirstNode(T);p!=NULL;p=NextNode(p))visit(p);
}
6. 中序线索二叉树找中序前驱
#include<stdio.h>
//线索二叉树结点
typedef struct ThreadNode
{char data;struct ThreadNode *lchild,*rchild;int ltag,rtag; //左右线索标志
}ThreadNode,*ThreadTree;//在中序线索二叉树中找到指定结点*p的中序前驱pre
//1.若p->ltag==1,则pre=p->lchild
//2.若p->ltag==0,找到左子树中,最后一个被中序遍历的结点 //找到以P为根的子树中,最后一个被中序遍历的结点
ThreadNode *LastNode(ThreadNode *p)
{//循环找到最右下结点(不一定是叶节点)while(p->rtag==0)p=p->rchild;return p;
}//在中序线索二叉树中找到结点p的前驱结点
ThreadNode *PreNode(ThreadNode *p)
{//左子树中最右下结点if(p->ltag==0)return LastNode(p->lchild);elsereturn p->lchild;
}//对中序线索二叉树进行逆向中序遍历
void RevInOrder(ThreadNode *T)
{for(ThreadNode *p=LastNode(T);p!=NULL;p=PreNode(p))visit(p);
}
7. 先序线索二叉树找先序后继
#include<stdio.h>
//线索二叉树结点
typedef struct ThreadNode
{char data;struct ThreadNode *lchild,*rchild;int ltag,rtag; //左右线索标志
}ThreadNode,*ThreadTree;//在先序线索二叉树中找到指定结点*p的先序后继next
//若p->rtag==1,则next=p->rchild
//若p->rtag==0:肯定有右孩子
// 1.有左孩子:根 左(根 左 右) 右 先序后继则为左孩子
// 2.没有左孩子: 根 右(根 左 右) 先序后继则为右孩子
ThreadNode *NextNode(ThreadNode *p)
{if(p->rtag==1)return p->rchild;else{if(p->ltag==0) //有左孩子:根 左(根 左 右) 右 先序后继则为左孩子return p->lchild;else //没有左孩子: 根 右(根 左 右) 先序后继则为右孩子return p->rchild;}}
7. 先序线索二叉树找先序前驱
先序遍历中,左右子树中的结点只可能是根的后继,不可能是前驱.
//除非从头开始先序遍历
#include<stdio.h>
//线索二叉树结点
typedef struct ThreadNode
{char data;struct ThreadNode *lchild,*rchild;int ltag,rtag; //左右线索标志
}ThreadNode,*ThreadTree;//在先序线索二叉树中找到指定结点*p的先序前驱pre
//若p->ltag==1,则Pre=p->lchild
//若p->ltag==0:肯定有左孩子
8. 后序线索二叉树找后序前驱
在后序线索二叉树中找到指定结点*p的后续前驱Pre
若p->ltag==1,则Pre=p->lchild
若p->ltag==0:肯定有左孩子
1.有右孩子:左 右(左 右 根) 根 后续前驱Pre则为右孩子
2.没有右孩子:左(左 右 根) 根 后序前驱Pre则为左孩子
#include<stdio.h>
//线索二叉树结点
typedef struct ThreadNode
{char data;struct ThreadNode *lchild,*rchild;int ltag,rtag; //左右线索标志
}ThreadNode,*ThreadTree;ThreadNode *NextNode(ThreadNode *p)
{if(p->rtag==1)return p->rchild;else{if(p->ltag==0) //有左孩子:根 左(根 左 右) 右 先序后继则为左孩子return p->lchild;else //没有左孩子: 根 右(根 左 右) 先序后继则为右孩子return p->rchild;}}
9. 后序线索二叉树找后序后继
在后序线索二叉树中找到指定结点*p的后续后继next
若p->rtag==1,则next=p->rchild
若p->rtag==0:肯定有右孩子
后续遍历中,左右子树中的结点只可能是根的前驱,不可能是后继
除非用后续遍历
#include<stdio.h>
//线索二叉树结点
typedef struct ThreadNode
{char data;struct ThreadNode *lchild,*rchild;int ltag,rtag; //左右线索标志
}ThreadNode,*ThreadTree;
三、树的表示法
1. 双亲表示法(顺序存储)
#include<stdio.h>
#define Max_Tree_Size 100 //树中最多节点数
typedef struct PTNode //树的结点定义
{ char data; //数据元素int parent; //双亲位置域
}PTNode;
typedef struct PTree //树的类型定义
{PTNode nodes [Max_Tree_Size]; //双亲表示int n; //结点数
}PTree;
2. 孩子表示法
#include<stdio.h>
#define Max_Tree_Size 100 //树中最多节点数
typedef struct CTNode
{int child; //孩子结点在数组中的位置struct CTNode *next; //下一个孩子
}CTNode;
typedef struct CTBox
{char data;struct CTNode *firstNode; //第一个孩子
}CTBox;typedef struct CTree
{CTBox nodes[Max_Tree_Size];int n,r; //结点数和根的位置
}CTree;
3. 孩子兄弟表示法
//二叉树的结点(链式存储)
typedef struct BiTNode
{char data;struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;//树的存储--孩子兄弟表示法
typedef struct CSNode
{char data;struct CSNode *firstchild,*nextsibling; //第一个孩子和右兄弟指针
}CSNode,*CSTree;
四、树的遍历
1. 树的先根遍历
树的先根遍历
若树非空,先访问根结点
再依次对每棵子树进行先根遍历
//树的先根遍历 (深度优先遍历)
void PreOrder(TreeNode *R)
{if(R!=NULL){visit(R); //访问根结点while(R还有下一个子树T){PreOrder(T); //先根遍历下一棵子树}}
}
//树的先根遍历序列与这棵树相对应的二叉树的先序序列相同。
2. 树的后根遍历.
//若树非空,依次对每棵子树进行后根遍历,最后再访问根结点
void PostOrder(TreeNode *R)
{if(R!=NULL){while(R还有下一个子树T){PostOrder(T); //后根遍历下一棵子树visit(R); //访问根结点}}
}
//树的后根遍历序列与这棵树相对应的二叉树的中序序列相同。
五、森林的遍历
先序遍历森林和依次对各个树进行先根遍历效果相同。
先序遍历森林效果等同于依次对二叉树的先序遍历。
森林的中序遍历,效果上等同于依次对各个树进行后根遍历。
中序遍历森林的效果等同于依次对二叉树的中序遍历
树 森林 二叉树
先根遍历 先序遍历 先序遍历
后根遍历 中序遍历 中序遍历
六、二叉排序树
左子树结点值 < 根节点值 < 右子树结点值
进行中序遍历,可以得到一个递增的有序序列
1. 存储
//二叉排序树结点
typedef struct BSTNode
{int key;struct BSTNode *lchild,*rchild;
}BSTNode,*BSTree;
2. 在二叉排序树中查找值为key的结点(非递归)
BSTNode *BST_Search(BSTree T,int key)
{while(T!=NULL && key!=T->key) //若树空或等于根节点值,则结束循环{if(key<T->key) //小于,则在左子树上查找T=T->lchild; elseT=T->rchild; //大于,则在右子树上查找}return T;
}
3. 在二叉排序树中查找值为key的结点(递归)
BSTNode *BST_Search(BSTree T,int key)
{if(T==NULL)return NULL; //空树,查找失败if(key==T->key)return T;else if(key<T->key)return BST_Search(T->lchild,key); //左子树中查找else return BST_Search(T->rchild,key); //右子树中查找
}
4. 二叉排序树的插入和删除
//二叉排序树结点
typedef struct BSTNode
{int key;struct BSTNode *lchild,*rchild;
}BSTNode,*BSTree;
插入思想:
若原二叉排序树为空,则直接插入结点;否则,若关键字k小于根节点值,则插入到左子树,若关键字k大于根节点值,则插入到右子树。
在二叉排序树插入关键字为k的新结点(递归实现),空间复杂度:O(h)
int BST_Insert(BSTree &T,int k)
{if(T==NULL) //原树为空,新插入的结点为根节点{T=(BSTree)malloc(sizeof(BSTNode));T->key=k;T->lchild=T->rchild=NULL;return 1; //返回1,插入成功!}else if(k==T->key) //树中存在相同关键字的结点,插入失败return 0;else if(k<T->key) //插入到左子树return BST_Insert(T->lchild,k);else //插入到右子树return BST_Insert(T->rchild,k);
}
按照str[]中的关键字序列建立二叉排序树
void Creat_BST(BSTree &T,int str[],int n)
{T=NULL; //初始时T为空树int i=0;while(i<n) //依次将每个关键字插入到二叉排序树中{BST_Insert(T,str[i]);i++;}
}
二叉排序树的删除:
先找到目标结点:
1.若被删除节点z是叶节点,则直接删除,不会破坏二叉排序树的性质.
2.若结点z只有一颗左子树或右子树,则让z的子树成为z父节点的子树,替代z的位置.
3.若结点z有左、右两颗子树,则令z的直接后继(或直接前驱)替代z,然后从二叉排序树中删去这个直接后继(或直接前驱),这样就转换成了第一或第二种情况.
左子树结点值 < 根结点值 < 右子树结点值
中序遍历可以得到一个递增的有序序列
z的后继:z的右子树中最左下结点(该节点一定没有左子树)
z的前驱:z的左子树中最右下结点(该节点一定没有右子树)
七、平衡二叉树
平衡二叉树(Balanced Binary Tree),检测平衡数(AVL)树----树上任一结点的左子树和右子树的高度之差不超过1.
结点的平衡因子=左子树高-右子树高
平衡二叉树结点的平衡因子的值只可能是-1,0,1
只要有任意节点的平衡因子绝对值大于1,就不是平衡二叉树
//平衡二叉树结点
#include<stdio.h>
typedef struct AVLNode
{int key; //数据域int balance; //平衡因子struct AVLNode *lchild,*rchild;
}AVLNode,*AVLTree;
1. LL—在A的左孩子的左子树中插入导致不平衡
LL平衡旋转(右单旋转)。
由于在结点A的左孩子(L)的左子树(L)上插入了新结点,A的平衡因子由1增至2,导致以A为根的子树失去平衡,需要一次向右的旋转操作。将A的左孩子B向右上旋转代替A成为根节点,将A结点向右下旋转成为B的右子树的根节点,而B原右子树则作为A结点左子树。
代码思路:指针指向:f->A,p->B,gf->lchild/rchild=A;实现f向右下旋转,p向右上旋转:其中,f是爹,p为左孩子,gf是f他爹1.f->lchild=p->rchild;2.p->rchild=f;3.gf.lchild/rchild=p;
2. RR—在A的右孩子的右子树中插入导致不平衡
RR平衡旋转(左单旋转)。
由于在结点A的右孩子®的右子树®上插入了新结点,A的平衡因子由-1减至-2,导致以A为根的子树失去平衡,需要一次向左的旋转操作。将A的右孩子B向左上旋转代替A成为根节点,将A结点向左下旋转成为B的左子树的根节点,而B的原左子树则作为A结点的右子树。
代码思路:指针指向:f->A,p->B,gf->lchild/rchild=A;实现f向左下旋转,p向左上旋转:其中,f是爹,p为左孩子,gf是f他爹1.f->rchild=p->lchild;2.p->lchild=f;3.gf.lchild/rchild=p;
3. LR—在A的左孩子的右子树中插入导致不平衡
LR平衡旋转(先左旋,再右旋)
由于在A的左孩子(L)的右子树(R)上插入新结点,A的平衡因子由1增至2,导致以A为根的子树失去平衡,需要进行两次旋转操作,先左旋后右旋,先将A结点的左孩子B的右子树的根结点C向左上旋转提升到B结点的位置,然后再把该C结点向右上旋转提升到A结点的位置。
4. RL—在A的右孩子的左子树中插入导致不平衡
LR平衡旋转(先右旋,再左旋)
由于在A的右孩子®的左子树(L)上插入新结点,A的平衡因子由-1减至-2,导致以A为根的子树失去平衡,需要进行两次旋转操作,先右旋后左旋。先将A结点的右孩子B的左子树的根结点C向右上旋转提升到B结点的位置,然后再把该C结点向左上旋转提升到A结点的位置。
数据结构复习(五)——树和二叉树相关推荐
- 【数据结构】_树与二叉树
目录 引言 一.什么是树? 1.树的定义 2.树的特点 3.树的表示法 二.树的一些基本术语 三.树的性质 四.什么是二叉树? 1.基本概念 2.二叉树的五种基本形态 3.二叉树的性质 五.满二叉树. ...
- 数据结构与算法——树和二叉树***
第五章 :树和二叉树 树和图是两种重要的非线性结构.线性结构中结点具有唯一前驱和唯一后继的关系,而非线性结构中结点之间的关系不再具有这种唯一性.其中,树形结构中结点间的关系是前驱唯一而后继不唯一,即元 ...
- Python__数据结构与算法——树、二叉树(实现先、中、后序遍历)
目录 一.树 二.二叉树 树和前面所讲的表.堆栈和队列等这些线性数据结构不同,树不是线性的.在处理较多数据时,使用线性结构较慢,而使用树结构则可以提高处理速度.不过,相对于线性的表.堆栈和队列等线性数 ...
- 数据结构实验二 树和二叉树的实现
广州大学学生实验报告 开课实验室:计算机科学与工程实验(电子楼418A) 2019年5月13日 学院 计算机科学与教育软件学院 年级.专业.班 计算机科学与技术172班 姓名 学号 17061 ...
- 【数据结构Note5】- 树和二叉树(知识点超细大全-涵盖常见算法 排序二叉树 线索二叉树 平衡二叉树 哈夫曼树)
文章目录 5.1 树和二叉树引入 5.1.1 树的概念 5.1.2 树的表示 5.1.3 树中基本术语 5.2 二叉树 5.2.1 概念 5.2.2 二叉树的性质 5.2.3 特殊的二叉树 5.2.4 ...
- 【数据结构_Day05】 树和二叉树、树和森林、哈夫曼树
1.树 根节点:非空树中无前驱结点的结点 结点的度:结点拥有的子树数 树的度:树内各结点的度的最大值 森林不一定是树,树一定是森林 2.二叉树 二叉树和树是不一样的概念 二叉树严格区分左子树和右子树, ...
- 数据结构-实验二 树和二叉树的实现
广州大学学生实验报告 开课实验室:计算机科学与工程实验(电子楼417) 2018年05月16日 学院 计算机科学与教育软件学院 年级.专业.班 网络161 姓名 卟咚君 学号 1606100 ...
- 数据结构知识点总结-树、二叉树、二叉树遍历、满二叉树、完全二叉树、查找二叉树、平衡二叉树、红黑树、B树、B+树
树 在计算器科学中,树(英语:tree)是一种抽象数据类型或是实现这种抽象数据类型的数据结构,用来模拟具有树状结构性质的数据集合.它是由n(n>0)个有限节点组成一个具有层次关系的集合.把它叫做 ...
- 数据结构与算法——树与二叉树详细分享
一.树 1.定义:由n个有限节点组成一个具有层次关系的集合,看起来像一颗倒挂的树,特点: 2.特点: a.每个节点有0个或多个子节点 b.没有父节点的节点称为根节点(A) c.每一个非根节点有且只有一 ...
- 数据结构与算法 | 树与二叉树
树的概念 二叉树的概念 树的概念和结构 树是一种非线性的数据结构,它是由n个有限结点组成一个具有层次关系的集合,把它叫做树是因为它看起来像一棵倒挂的树,如图所示 有一个特殊的结点,称为根节点,根节点没 ...
最新文章
- 什么是动态DNS 动态DNS有什么用
- PIX 525下的怪问题(需在防火墙后的同子网上激活之后才能在INTERNET上使用)?...
- SQL Server Integration Services 包的开发与部署初探
- Big Data應用:以玩家意見之數據分析來探討何謂健康型線上遊戲(上)
- unbalanced enable irq 问题的解决 以及共享的gpio中断引起的问题
- 河南上oracle客户,解决Oracle监听服务报错
- Spring5(3)---Spring5概述
- spark中local模式与cluster模式使用场景_Spark内核及通信框架概述-针对面试(后面有源码分析)...
- 敏捷开发般若敏捷系列之八:敏捷的未来会怎样?
- ps快捷键大全(表格汇总)
- vue-draggle实现元素拖动,放大,缩小,多元素一起改变位置
- OSChina 周三乱弹 ——程序员是将咖啡转变成代码的工具
- Babylonjs 官网demo预览图合集整理 带说明
- rundll32.exe传入参数
- Unity shader 实现圆角矩形
- 什么从什么写短句_照样子写句子.(写清“谁或什么 “在什么地方 “做什么或怎么样 ) 例1:小朋友在河边种树. 例2:麻雀在窝里睡着了. 题目和参考答案——青夏教育精英家教网——...
- [精华] nucleus实时操作系统MTK手机软件系统工程和配置简介
- 磁感应强度、磁场强度、磁动势之三者间的关系
- 【计算机网络】网络层:路由器的构成
- 外部表不是预期的格式-excel
热门文章
- android开发:Theme.Light.NoTitleBar和Theme.Light.NoTitleBar.Fullscreen的区别
- 2021 AAAI best Paper - Informer-2020 学习记录
- matlab实现ica,Matlab用ICA进行话语分离
- 求大神赐教Maven中子模块之间无法建立依赖关系问题
- 笔记本进入pe却看不到计算机硬盘,11代cpu笔记本进pe看不到硬盘解决方法(PE完美解决)...
- python2和python3一些不同
- 微信开发者工具 网络连接失败
- Windows音频录制软件哪个好
- 关于HTTP协议之谈网址URL劫持的影响
- 饥荒机器人怎么解锁_饥荒机器人怎么玩 饥荒机器人详细玩法