C语言数据结构基础学习笔记——树
树是一种一对多的逻辑结构,树的子树之间没有关系。
度:结点拥有的子树数量。
树的度:树中所有结点的度的最大值。
结点的深度:从根开始,自顶向下计数。
结点的高度:从叶结点开始,自底向上计数。
树的性质:①树的结点数等于所有结点的度数加1;②度为m的树中第i层上至多有mi-1个结点(i>=1);③度为h的m叉数至多有(mh-1)/(m-1)个结点;④具有n个结点的m叉树的最小高度为[logm(n(m-1)+1)]。
树的表示方法:
①双亲表示法(顺序表示法):根节点parent=-1
typedef char ElemType;
typedef struct TNode{
ElemType data; //结点数据
int parent; //该结点双亲在数组中的下标
}TNode; //结点数据类型
#define MaxSize 50
typedef struct{
TNode nodes[MaxSize]; //结点数组
int n; //结点数量
}Tree; //树的双亲表示结构
②孩子表示法:把每个孩子的孩子结点排列起来存储成一个单链表,n个结点就有n个单链表,n个单链表的头指针又存储在一个顺序表(数组)中
typedef char ElemType;
typedef struct CNode{
int child; //该孩子在表头数组的下标
struct CNode *next; //指向该结点的下一个孩子结点
}CNode,*Child; //孩子结点数据类型
typedef struct{
ElemType data; //结点数据域
Child firstchild; //指向该结点的第一个孩子结点
}TNode; //孩子结点数据类型
#define MaxSize 100
typedef struct{
TNode nodes[MaxSize]; //结点数据域
int n; //树中的结点个数
}Tree; //树的孩子表示结构
③孩子兄弟表示法:分别指向孩子结点和兄弟结点,其结点结构为:
typedef char ElemType;
typedef struct CSNode{
ElemType data; //该结点的数据域
struct CSNode *firstchild,*rightsib; //指向该结点的第一个孩子结点和该结点的右兄弟结点
}CSNode; //孩子兄弟结点数据类型
二叉树:①每个结点最多有两棵子树;②左右子树有顺序。
二叉树的种类:①斜二叉树;②满二叉树;③完全二叉树。
满二叉树是绝对的等腰三角形,每一个非叶子结点都有两个子树,而完全二叉树的结点个数随意,只需满足其层序遍历的序号与满二叉树相同即可。
二叉树的顺序存储:用一组地址连续的存储单元依次自上向下,自左至右存储完全二叉树上的结点元素,非完全二叉树需在对应空缺编号处保留数组空位,这是一种极其浪费的存储方式。
二叉树的链式存储:
①二叉链表:两个指针指向左右孩子结点。其实现为:
typedef struct BiTNode{
    ELemType data;
    struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;  
②三叉链表:在二叉链表的基础上添加一个指针指向双亲。
二叉树的遍历:按某种次序依次访问树中的每个结点,使得每个结点均被访问人一次,而且仅被访问一次。
有以下四种方法:
①先序遍历:a.访问根节点;b.先序遍历左子树;c.先序遍历右子树。
递归实现:
void PreOrder(BiTree T){
    if(T!=NULL){
        printf("%c",T->data);        //访问根节点
        PreOrder(T->lchild);         //递归遍历左子树
        PreOrder(T->rchild);         //递归遍历右子树
    }
} 
非递归实现:在实现过程中利用了栈的思想
void PreOrder(BiTree b){
    InitStack(s);
    BiTree p=b;                        //工作指针p
    while(p||!IsEmpty(s)){
        while(p){
            printf("%c",p->data);
            Push(s,p);                 //进栈
            p=p->lchild;
        }
        if(!IsEmpty(s)){
            p=P0p(s);
            p=p->rchild;
        }
    }
} 
②中序遍历:a.中序遍历左子树;b.访问根节点;c.中序遍历右子树。
递归实现:
void InOrder(BiTree T){
    if(T!=NULL){
        InOrder(T->lchild);          //递归遍历左子树
        printf("%c",T->data);        //访问根节点
        InOrder(T->rchild);          //递归遍历右子树
    }
} 
非递归实现:
void InOrder(BiTree b){
    InitStack(s);
    BiTree p=b;
    while(p||!IsEmpty(s)){
        while(p){
            Push(s,p);
            p=p->lchild;
        }
        p=Pop(s);
        printf("%c",p->data);
        p=p->rchild;
    }
} 
③后序遍历:a.后序遍历左子树;b.后序遍历右子树;c.访问根节点。
递归实现:
void PostOrder(BiTree T){
    if(T!=NULL){
        PostOrder(T->lchild);        //递归遍历左子树
        PostOrder(T->rchild);        //递归遍历右子树
        printf("%c",T->data);        //访问根节点
    }
} 
非递归实现:
void PostOrder(BiTree b){
    InitStack(s);
    BiTree p=b,r=NULL;                        //工作指针p,辅助指针r
    while(p||!IsEmpty(s)){                    //从根节点到最左下角的左子树都入栈
        if(p){
            Push(s,p);
            p=p->lchild;
        }
        else{
            GetTop(s,p);                      //取栈顶,不是出栈
            if(p->rchild&&p->rchild!=r)       //如果栈顶存在右子树且未被访问过,就去访问
                p=p->rchild;
            else{                             //不存在右子树或者被访问过,则出栈
                Pop(s,p);
                printf("%c",p->data);
                r=p;
                p=NULL;
            }
        }
    }
} 
④层序遍历:从上向下逐层遍历,在同一层中,从左到右对结点逐个访问。
层序遍历没有递归实现,只有非递归实现:其采用了队列的思想
void LevelOrder(BiTree b){
    InitQueue(Q);
    BiTree p;
    EnQueue(Q,b);                      //根结点入队
    while(!IsEmpty(Q)){                //队列不空循环
        DeQueue(Q,p)                   //队头元素出队
        printf("%c",p->data);
        if(p->lchild!=NULL)
            EnQueue(Q,p->lchild);
        if(p->rchild!=NULL)
            EnQueue(Q,p->rchild);
    }
} 
如何将一棵树转化成二叉树:①将同一结点的各个孩子用线串起来;②将每个结点的子树分支,从左往右,除了第一个以外全部删除。
将二叉树转化成树:将二叉树从上到下分层,并调节成水平方向,之后是正向转化的逆过程。
一个重要结论:n个结点的二叉链表,每一个结点都有指向左右孩子的结点指针,所以一共有2n个指针,而n个结点的二叉树一共有n-1条分支,也就是存在2n-(n-1)=n+1个空指针。
线索二叉树:指向前驱和后继的指针称为线索,加上线索的二叉链表就称为线索链表,相应的二叉树就称为线索二叉树。对二叉树以某种次序遍历使其变成线索二叉树的过程叫作线索化。
下面我们以中序遍历作为例子,实现线索二叉树,并对其遍历:
线索二叉树的实现:
typedef struct ThreadTNode{
    ELemType data;
    struct ThreadTNode *lchild,*rchild;
    int ltag,rtag;            //tag=0指向孩子,tag=1指向前驱或者后继
}ThreadTNode,*ThreadTree;
void InThread(ThreadTree &p,ThreadTree &pre){
    //pre指向中序遍历时上一个刚刚访问过的结点,初值为NULL
    if(p){
        InThread(p->lchild,pre);
        if(p->lchild==NULL){
            p->lchild=pre;
            p->ltag=;
        }
        if(pre!=NULL&&pre->rchild==NULL){
            pre->rchild=p;
            pre->rtag=;
        }
        pre=p;
        InThread(p->rchild,pre);
    }
}
对线索二叉树进行中序遍历:
void InOrderTraverse(ThreadTree T){
    ThreadTree p=T;
    while(p){
        while(p->ltag==) p=p->lchild;
        printf("%c",p->data);
        while(p->ltag==&&p->rchild){
            p=p->rchild;
            printf("%c",p->data);
        }
        p->rchild;
    }
} 
哈夫曼树中相关概念:
权:树中结点相关的数值;
路径长度:从树中某个结点到另一个结点之间的分支数目(经过的边数);
带权路径长度:从树的根结点到任意结点的路径长度与该结点权值的乘积;
树的带权路径长度:树中所有结点带权路径长度的和。
哈夫曼树的定义:含有n个带权叶子结点的二叉树中,其中带权路径长度最小的二叉树,也称为最优二叉树。
C语言数据结构基础学习笔记——树的更多相关文章
- C语言数据结构基础学习笔记——B树
		
2-3树:是一种多路查找树,包含2结点和3结点两种结点,其所有叶子结点都在同一层次. 2结点:包含一个关键字和两个孩子(或没有孩子),其左孩子的值小于该结点,右孩子的值大于该结点. 3结点:包含两个关 ...
 - C语言数据结构基础学习笔记——C语言基础
		
抽象数据类型(ADT)是指一个数学模型以及定义在该模型上的一组操作,通常用(数据对象,数据关系,基本操作集)这样的三元组来表示抽象数据类型. 数据结构是相互之间存在一种或多种特定关系的数据元素的集合, ...
 - C语言数据结构基础学习笔记——动态查找表
		
动态查找表包括二叉排序树和二叉平衡树. 二叉排序树:也叫二叉搜索树,它或是一颗空树,或是具有以下性质的二叉树: ①若左子树不空,则左子树上所有结点的值均小于它的根结点的值: ②若右子树不空,则右子树上 ...
 - C语言数据结构基础学习笔记——图
		
图(G)由顶点集(V)和边集(E)组成,G=(V,E) 常用概念: ①V(G)表示图G中顶点的有限非空集,V永不为空: ②用|V|表示图G中顶点的个数,也称为图G的阶: ③E(G)表示图G中顶点之间关 ...
 - C语言数据结构基础学习笔记——栈和队列
		
之前我们学过了普通的线性表,接下来我们来了解一下两种特殊的线性表——栈和队列. 栈是只允许在一端进行插入或删除的线性表. 栈的顺序存储结构也叫作顺序栈,对于栈顶指针top,当栈为空栈时,top=-1: ...
 - C语言数据结构基础学习笔记——静态查找表
		
查找:在数据集合中寻找满足某种条件的数据元素的过程称为查找. 查找表:用于查找的数据集合称为查找表,一般有以下操作:①查找是否在表中:②查找属性:③进行操作. 查找表又分为: ①静态查找表:只可以进行 ...
 - C语言数据结构基础学习笔记——基础线性表
		
线性表是指具有相同数据类型的n(n>=0)个数据元素的有限序列,它具有一个表头元素和一个表尾元素,并且每一个数据元素最多只有一个直接前驱和一个直接后继. 线性表的顺序存储也叫作顺序表,它的特性是 ...
 - Oracle基础学习笔记
		
Oracle基础学习笔记 最近找到一份实习工作,有点头疼的是,有阶段性考核,这...,实际想想看,大学期间只学过数据库原理,并没有针对某一数据库管理系统而系统的学习,这正好是一个机会,于是乎用了三天时 ...
 - 尚学堂JAVA基础学习笔记
		
目录 尚学堂JAVA基础学习笔记 写在前面 第1章 JAVA入门 第2章 数据类型和运算符 第3章 控制语句 第4章 Java面向对象基础 1. 面向对象基础 2. 面向对象的内存分析 3. 构造方法 ...
 
随机推荐
- Unity中有限状态机的用法教程
			
Unity开发VR之Vuforia 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- ...
 - jmeter 写正则表达式
			
():括起来的部分就是要提取的. .:匹配任何字符串. +:一次或多次. ?:不要太贪婪,在找到第一个匹配项后停止. 需要根据要取的数据取值 jt: eyJhbGciOiJSUzI1NiJ9.ey ...
 - 不应该使用String.valueOf的场景
			
今天在接口中接收参数转换String时遇到一个巨大的坑,也是自己疏忽大意所致---- 事情是这样的,项目中接口的公共入参对象为Map<String,Object>,而sql中需要的参数为S ...
 - Servlet中的编码问题
			
对于response.setContentType()和response.setCharacterEncoding()的理解: 经过一些实践,对着两个方法有了一些自己的理解,有可能今后的学习中会发现自 ...
 - Python环境os模块功能
			
功能 语句 得到当前工作目录,即当前Python脚本工作的目录路径: os.getcwd() 返回指定目录下的所有文件和目录名: os.listdir() 函数用来删除一个文件: os.remove( ...
 - C++跨平台集成websocketpp
			
之前给公司写了一个用于消息交互的服务器,移植到Linux上之后发现H5-Websocket模块经常出问题,而该模块是另一位已经离职同事编写的,所以修改和维护都存在一定的困难,索性就直接把这个模块替换掉 ...
 - win10 安装 face_recognition
			
环境:Python 3.6.4 |Anaconda, Inc.| (default, Jan 16 2018, 10:22:32) [MSC v.1900 64 bit (AMD64)] on win ...
 - js入门 关于js属性及其数据类型(详解)
			
1. js的本质就是处理数据.数据来自于后台的数据库. 所以变量就起到一个临时存储数据的作用. ECMAScript制定了js的数据类型. 数据类型有哪些? 1. 字符串 String 2. 数字 ...
 - js入门关于js‘i++’‘++i’和‘i--’‘--i’计算的问题
			
一,i++和++i; i++是先赋值在运算,++i是先运算在赋值: 例如:var a=1 a++:在运算时是按照1计算的:但在下面再次出现时是按照2进行运算: ++a:在运算时是按照2计算的:在下面再 ...
 - C++ 状态机接口
			
最近的状态极差,甚至代码也写不下去了.给自己手臂上的两刀没有任何的作用,看来早已经是麻痹了. 一直想弄一个勉强能用的状态机,用于在各种涉及到状态转换的时候用到,然而脑子并不是太清醒. 先放在这里一个接 ...