第六章 树
概念:
根结点是唯一的。
度:结点拥有的子树数(只是一层,根结点并不是最大的)。度为0叫做叶结点。度不为0的结点称为非终端结点或分支结点。树的度是树内各节点的最大值。
深度、高度:有多少层。
线性表与树:
线性表:第一个数据元素:无前驱。 最后一个数据元素:无后继 中间元素:一个前驱一个后继
树:根结点:无双亲。 叶结点:无孩子,可以多个 中间结点:一个双亲多个孩子
树的存储结构之双亲表示法:
双亲只是一个,并不是两个。
除了根结点外,可能没有孩子,但一定有双亲。以一组连续空间存储树的结点,每个结点,都有一个指示器,存双亲结点的位置。
data | parents |
其中data是数据域,存储结点的数据信息。而parents是指针域,存储该结点的双亲在数组中下标。代码:
#define MAX_TREE_SIZE 100
typedef int TElemType; /*树结点的数据类型,目前暂定义为整型*/
typedef struct PTNode /*结点结构*/
{
TElemType data;
int parent;
}PTNode;
typedef struct /*树结构*/
{
PTNode nodes[MAX_TREE_SIZE]; /*结点数组*/
int r,n; /*根的位置和结点*/
}PTREE;
根节点没有双亲。所以根节点位置parents设为-1。
孩子表示法:把每个孩子结点排列起来,以单链表作存储结构,则n个结点有n个孩子链表,如果是叶子结点则此单链表为空,n个头指针又组成一个线性表,采用顺序存储结构,存放进一个一维数组。
双亲孩子表示法:在上面的在加上双亲的位置。
两种结点结构:
孩子链表结点:child数据域但存储的是下标,next指针域,指向下一个孩子。
#define MAX_TREE_SIZE 100
//孩子结点
typedef struct CTNode
{
int child; //孩子结点下标
struct CTNode *next; //指向下一个孩子结点的指针
}*ChildPtr
data是数据域,存储某结点的数据信息。firstchild是头指针域,存储该节点的孩子链表的头指针。中间还要加个parents。
//表头结构
typedef char ElemType;
typedef struct
{
ElemType data;//存放在树中结点的数据
int parent; //存放双亲下标
ChildPtr firstchild;//指向第一个孩子的指针
}CTBox;
//树结构
typedef struct
{
CTBoxnodes[MAX_TREE_SIZE];//结点数组
int r,n;
}
二叉树的定义
下面没有三个叉就是二叉树,最多是两个就行。左和右不一样。
斜树:全部往左斜和全部往右斜。
满二叉树:叶子在一层,都有左右子树。
完全二叉树:对一棵具有 n 个结点的二叉树按层序编号,如果编号为 i (l<:i<n) 的结点与同 样深度的满二叉树中编号为 i 的结点在二叉树中位置完全相同,则这棵二叉树称为完 全二叉树。(从左到右的,最多差一层)满一定是完全。
二叉树的性质
二叉树第i层上至多有2^(i-1)个结点。(满二叉)
深度为k的二叉树至多有2^k-1个结点。
后面性质不看了,又不是要考研。
二叉树的存储结构
二叉树的顺序存储结构:用一维数组。
二叉链表:
一个数据域和两个指针域。
/*二叉树的二支键-*-结点结构定义*/
typedef struct BiTNode /*结点结构*/
{
TElemType data; /*结点数据*/
strcut BiTNode *lchild,*rchild; /*左右孩子指针*/
}BiTNode, *BLTree;
遍历:https://blog.csdn.net/qiki_tangmingwei/article/details/79325611
1.前序遍历。先根、左、右。
一个tree只有一个lchild一个data一个rchild。
2.中。左、根、右。
3.后。先叶子后结点。左、右、根。
4.层。一层一层。
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#define MAXSIZE 100;
/*二叉树的二叉链表结点结构定义"*/
typedef struct BiTNode
{
char data;
struct BiTreeNode *left;
struct BiTreeNode *right;
}BiTreeNode,*BiTree;
/**二叉树的建立--按照先序方式建立--插入**/
void CreateBiTree(BiTree *T)
{
char val;
scanf("%c",&val);
if(val == '#')
*T = NULL; //null表示为空枝
else
{
*T = (BiTree)malloc(sizeof(BiTreeNode)); //BiTReee=BiTNode *
(*T)->data = val;
CreateBiTree(&(*T)->left);
CreateBiTree(&(*T)->right);
}
}
/**先序遍历 根左右**/
void PreOrderTravel(BiTree T)
{
if(T==NULL)
return;
printf("%c ",T->data);
PreOrderTravel(T->left);
PreOrderTravel(T->right);
}
/**中序遍历 左根右**/
void InOrderTravel(BiTree T)
{
if(T==NULL)
return;
InOrderTravel(T->left);
printf("%c ",T->data);
InOrderTravel(T->right);
}
/**后序遍历 左右根**/
void TailOrderTravel(BiTree T)
{
if(T==NULL)
return;
TailOrderTravel(T->left);
TailOrderTravel(T->right);
printf("%c ",T->data);
}
int main()
{
printf("测试代码\n");
BiTree T;
T = (BiTree)malloc(sizeof(BiTreeNode));
printf("请给二叉树按照先序方式依次输入结点的值(空结点为#):\n");
CreateBiTree(&T);
printf("先序方式遍历结果:\n");
PreOrderTravel(T);
printf("\n");
printf("中序方式遍历结果:\n");
InOrderTravel(T);
printf("\n");
printf("后序方式遍历结果:\n");
TailOrderTravel(T);
printf("\n");
return 0;
}
typedef有取别名的作用,所以BitNode的意思是struct BitNode{...),BiTree的意思是struct BitNode{...)*。
BiTree &T 是取指针地址的意思,如同int &a,取a得地址一样。
BitNode *T 和 BiTree T 是定义结构指针变量。
线索二叉树:
上述有许多的NULL,造成资源浪费。
线索:指向前驱和后续结点。加上线索的二叉链表称为线索链衰,相应的二叉树就.称为线索二叉树
ltag是0时,指向该结点的左孩子,为1时指向前驱。
rtag是0时,指向该节点的右孩子,为1时指向后继。
#include <stdio.h>
#include <stdlib.h>
typedef char ElemType;
typedef enum {link,thread}PointerNag;//link=0 ,thread=1
typedef struct BiThrNode
{
char data;
struct BiThrNode *lchild,*rchild;
PointerNag ltag,rtag;
}BiThrNode,*BiThrTree;
//全局变量。始终指向刚刚访问过的结点
BiThree pre;
//创建一个二叉树
void createtree(BiThrNode *T)
{
char c;
scanf("%c",c);
if(' '==c)
{
*T=NULL;
}
else
{
*T=(BiThrNode)malloc(sizeof(BiThrNode));
(*T)->data=c;
(*T)->ltag=link;
(*T)->rtag=link;
createtree(&(*T)->lchild);
createtree(&(*T)->rchild);
}
}
//中序遍历线索话
void InThreading(BiThrNode *T)
{
if( T )
{
InThreading(T->lchild); //递归左孩子
if(!T->lchild) //如果该结点没有左孩子,设置ltag为thread,并把lchid指向上一个访 问的结点(前驱)
{
T->ltag=thread;
T->lchild=pre;
}
if(!pre) //后继还不知道,只能把上一个结点的后一个设为当前的。
{
pre->rtag=thread;
pre->rchild=T;
}
pre=T;
InThreading(T->rchild);
}
}
设置一个头结点,头结点左链lchild指向根节点1,头结点右链rchil向中序遍历的最后一个结点的后继2。
二叉树的中序遍历的第一个结点lchild指向头结点3,最后一个结点指向头结点4.
/* T 指向头结点.头结点在左链lchild 指向根结点,头结点右链 rchild 指向中序遍历的最后一个结点。 中序遍历二又线索链表表示的二又树 T */
int InorderTrading(BiThrTree *P, BiThrTree t)
{
*P = (BiThrTree)malloc(sizeof(BiThrNode));
(*P)->ltag=link;
(*P)->rtag=thread;
if(!T) //空树指向本身
{
(*p)->lchild=p;
}
else //不是空树
{
(*P)->lchild=*T;
pre = *P;
InThreading(T);
pre->rchild=*P;
pre->rtag=thread;
(*P)->rchild=pre;
}
}
没有仔细看,哪天心情好在仔细看一看。
荷夫曼编码
创建一个优先级队列。
按次数、权重,从小到大排列。
创建一个树。
最小的两个构成新结点。
左边是0,右边是1.
然后,encode、decode。
代码太多了,小甲鱼讲了,但是45分钟不想看了,看下一章吧。