数据结构——树

树是有限集合: 有一个根。

root 根 subtree 子树

节点拥有的子树数成为结点的度;度为0 的节点称为叶节点


树结构: 根结点 无双亲 唯一, 叶节点: 无孩子 可以多个 中间节点 一个双亲多个节点。

抽象数据:
ADT:树

Data: 一个结点和若干个字数 树中节点句用相同的数据类型

operation:

InitTree(*T):
DestoryTree(*T)
createTree(*T)
CleareTree(*T)
TreeEmpty(T);
TreeDepth();
Root(T)
Value(T,cur_e); 返回结点的值
Assign(T,cur_e,value);给树的节点赋值
Parent(T,cur_e);
LeftChild(T,cur_e);
RightChild(T,cur_e);
InsertChild(T,*p,i,c); P指向T的某个节点 i为指向P的度加1
DeleteChild(*T,*p,i); p指向T的某个节点,i为节点p的度 删除T中P所指向的第i棵子树

endData


data : parent

#define MAX_TREE_SIZE 100
typedef int elemtype;树的数据类型
typedef struct PTNode 树的节点
{
elemtype data;
int parent;
}PTNode;

typedef struct 树的结构
{
PTNode node[MAX_TREE_SIZE]; 节点数组
int r,n; 根的位置和节点数
} Ptree;

表示双亲,根结点的位置域为-1
下表 data parent
0 A -1
1 B 0
2 C 0
3 D 1
4 E 2
5 F 2
6 G 3
7 H 3
8 I 3
9 J 4

很容易找到双亲时间复杂度 O(1)
找孩子节点 要便利整个结构

设置孩子域:

index data parent fristchild

0 A -1

把每个结点的孩子排列起来,以单链表作为i存储结构。则n个节点有n个孩子链表
data fristchild(指针域)

#defiine MAX_TREE_SIZE 100
typedef struct CTNode 节点
{
int child;
struct CTNode *next;

}*ChildPtr;

typedef struct 表头结构
{
elemtype data;
ChildPtr fristchild;
}CTBox;

typedef struct
{
CTBox nodes[MAX_TREE_SIZE];
int r,n;
}CTree;
方便查找子节点 双亲节点麻烦

#defiine MAX_TREE_SIZE 100
typedef struct CTNode 节点
{
int child;
int parent;
struct CTNode *next;

}*ChildPtr;

typedef struct 表头结构
{
elemtype data;
ChildPtr fristchild;
}CTBox;

typedef struct
{
CTBox nodes[MAX_TREE_SIZE];
int r,n;
}CTree;
双亲孩子表示法

typedef struct CSNode
{
elemtype data;
struct CSNode *fristchild , *rightsid;

} CSNode,*CSTree;

二叉树:
1 度不大于2 有顺序
状态:

空二叉树
只有一个个根结点

二叉树的链表表示:

typedef struct BitNode
{
elemtype data;
struct BitNode *lchild,*rchild;

}BitNode,*BiTree;

前序遍历: 先访问根结点 再访问左节点 后访问右节点
void preOrderTraverse(BiTree T)
{
if(T == NULL)
return;
printf("%c",T->data)
preOderTraverse(T->lchild);
preOderTraverse(T->rchild);


中序遍历: 从根开始(不访问)先访问左字数 在访问根 最后访问右子树

void InOderTraverse(BiTree T)
{
if(T == NULL)
return;
InorderTraverse(T->lchild);
printf("%c",T->data);
InorderTraverse(T->rchild);
}

后序遍历: 先访问左右子节点, 最后访问根结点
void PostOrderTravese(BiTree T)
{
if(T==NULL)
return;
PostOrderTraverse(T->lchild);
PostOrderTreavese(T->rchild);
printf("%c",T->data);
}
层序遍历: 逐层访问

二叉树的建立:
void CreateBiTree(BiTree *T)
{
elemtype ch;
scanf("%c",&ch);
if(ch == '#')
{
*T=NULL;
}
else
{
*T = (BiTree)malloc(sizeof(BiTNode);
if(!*T)
exit(OVERFLOW);
(*T)->data = ch;
CreateBigTree(&(*T)->lchild); //构建左子树
CreateBiTree(&(*T)->rchild);

}
return;
对于n个结点的二叉树链表,每个节点指向左右孩子的两个指针,所以共有2n个指针与,而n个结点的二叉树有n-1条分支线树 存在2n-(n-1) = n+1个空指针

}

线索二叉树结构的实现:

typedef enum {link, Thread} PointerTag; Link ==0 表示指向左右孩子
Thread 表示指向前驱或则后记
typedef struct 而茶线索存储结构
{
elemtype data;
struct BigThrNode *lchild,*rchild;
PointterTag Ltag; 标志
PointerTag rtag;

}BigThrNode,*BigThrTree;
实质是将空指针改编为前去或则后记
在便利中修改指针:

BiTree pre; 全局变量
void InThreading(BiThrTree p)
{
if(p)
{
InThreading(p->lchild);
if(!p->lchild)
{
p->Ltag=Thread; //前驱线索
p->lchild = pre;//左孩子指向前驱
}
if(!p->rchild) //设置前驱的后继
{
pre->RTag = Thread;
pre->rchild = p;
}
pre = p;//保持pre指向p的前驱
InThreading(p->rchild);第归右子树线索化

//中序遍历一样
}
}

遍历:
T 指向头结点 头结点左联lchild指向根结点 头结点右连rchild 指向中序遍历的最后一个结点 中序遍历二叉线索表 表示的二叉树

status InOrderTraverse_Thr(BiTree T)
{
BiThrTree p;
P=T->lchild; p 指向根结点
while(p!=T) 空树便利结束
{
while(p->LTag ==link) // 当LTag ==0 时循环到中序序列第一个节点
p=p->lchild;
printf("%c",p->data);
}
while(p->RTag == Thead && p->rhcild!=T) //p->rchild 不等于头结点 p是一个后记指针
{
p=p->rchild;//指向后继
printf("%c",p->data);
}

}return ok;


图:grap 有穷非空个顶点
G(V,E) G 是图 V顶点集合 E 边的集合
无向边 v1 到 v2 没有方向 无向边 (v1,v2);
任意两个顶点之间的边都是无向边, 陈为无向图 顶点的边无序对 (A,D)
V无向图 G1=(V1,{E1}), 顶点集合 V1={A,B,C,D} 边集合 E1={(A,B),(B,C),(D,A),(A,C)}

有向边: 有方向的边,也成为弧 <A,D> A弧尾 D为弧头 有向图 G2=(V2,{E2}); V2={A,B,C,D} E2 = {<A,D>,<B,A>,<C,A>,<B,C>};
与图的边相关的树: 权 带权的图称网

子图


顶点与边的关系: 相邻接 顶点的度是和A相关的边的数目

有相图的出度,《V,V1》v为弧尾弧的目 入度以v为头的弧的数目

path 是一个顶点序列

任意两个顶点,都是连同的 陈为连通图

极大连通子图陈为连通分量

任意两点都有路径 g是强连通图, 集强大连通子图成为有相图的强连通分量

原文地址:https://www.cnblogs.com/countryboy666/p/11087944.html