树:
是n(n>=0)个节点的有限集。n=0时称为空树。
在任意一颗非空树中:
(1)有且仅有一个特定的称为根的节点;
(2)当n>1时,其余节点可分为m(m>0)个互不相交的有限集T1,T2、...、Tm,其中
每一个集合本身又是一棵树,并且称为根的子树。
节点:
a.根节点
b.内部节点
c.叶结点
度:一个节点拥有的子节点个数。
深度:树的层数。
二叉树
特点:
a.每个节点最多两个子树。度<=2
b.左子树和右子树是有顺序的,不能随意颠倒。
c.即使树中某节点只有一棵子树,也要区分左右子树。
特殊二叉树:
1.斜树:
链表是特殊的二叉树(斜树)。
2.满二叉树
3.完全二叉树
性质:
1.第i层上至多有2i-1 个节点(i>=1)
2.深度为k的二叉树至多有2k-1个节点(k>=1)
3.任意二叉树,终端节点为n0,度为2的节点数位n2;则n0=n2+1
4.具有n个节点的完全二叉树的深度为【log2n】+1
5.如果对一颗有n个结点的完全二叉树的结点按层序编号,对任意i:
a.如果i=1,则结点i是二叉树的根,无双亲;如果i>1,则其双亲是结点【i/2】
b.如果2i>n,则结点i无左孩子,否则其左孩子的结点2i
c.如果2i+1>n,则结点i无右孩子;否则其右孩子是结点2i+1.
顺序存储适用性不强,考虑使用链式存储结构。
二叉链表:
数据结构:
typedef char dataType; typedef struct bintree{ dataType data; struct bintree* lch; struct bintree* rch; }BiTNode,*pBiTNode;
一个数据域,两个孩子指针域。
建立二叉树(前序):
void createBinTreeByPre(pBiTNode* T,char ch) { if (ch == '#') { *T = NULL; } else { *T = (pBiTNode)malloc(sizeof(BiTNode)); (*T)->data = ch; g_p++; createBinTreeByPre(&((*T)->lch),*g_p); g_p++; createBinTreeByPre(&((*T)->rch),*g_p); } }
前序建立二叉树,实质上是将树按照前序方式输入,
比如:
这样的一颗二叉树的前序遍历为:ABDGHCEIF
但是在建立二叉树的时候,我们要引入一个符号来表示这个树结束,即叶子的两个指针应该为NULL。
一般引入‘#’作为结束,所以对于上面那幅图 我们要将它补全。
对于G H I 这有的结点,同样和F一样。
建立二叉树的时候,输入方式为:
char *g_ary = "ABDG##H###CE#I##F##";
这有就建立如pic:tree-1所示的树了。
访问树:
对于我们人,可以形象的看到树的结构,但是在计算机中存储是按线性方式,要想遍历,只能按照一个规定的顺序遍历。
对于二叉树,我们分为 前序遍历,中序遍历,后序遍历,层次遍历。
前中后是对根节点(或者子树的根)为对象而区分的。
前序:先访问中,然后对左右索引。
中序:先索引左,访问中,索引右。
后序:先索引左,索引右,访问中。
这里索引和访问换个词语解释:
索引:移动。
访问:得到该节点信息。
代码:
//前序遍历 void preVisitTree(pBiTNode r) { if(r == NULL) { return ; } printf(" %c ",r->data); preVisitTree(r->lch); preVisitTree(r->rch); } //中序遍历 void midVistitTree(pBiTNode r) { if (r == NULL) { return ; } midVistitTree(r->lch); printf(" %c ",r->data); midVistitTree(r->rch); } //后序遍历 void nextVistitTree(pBiTNode r) { if (r == NULL) { return ; } nextVistitTree(r->lch); nextVistitTree(r->rch); printf(" %c ",r->data); }
测试:
int _tmain(int argc, _TCHAR* argv[]) { pBiTNode root=NULL; createBinTreeByPre(&root,*g_p); printf("pre:"); preVisitTree(root); printf("\n"); printf("mid:"); midVistitTree(root); printf("\n"); printf("next:"); nextVistitTree(root); printf("\n"); getchar(); return 0; }
代码中的g_p是全局指针变量:(只能想到这个比较不好的方法,如果有人知道好的,请告诉我)
char *g_p = g_ary;
结果:
完整代码:
// tree.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <stdlib.h> //char g_ary[] = {'3','4','#','7','#','#','5','#','#'}; //char *g_ary = "ABDG##H###CE#I##F##"; char *g_ary = "ABDH##I##EJ###CF##G##"; char *g_p = g_ary; typedef char dataType; typedef struct bintree{ dataType data; struct bintree* lch; struct bintree* rch; }BiTNode,*pBiTNode; void createBinTreeByPre(pBiTNode* T,char ch) { if (ch == '#') { *T = NULL; } else { *T = (pBiTNode)malloc(sizeof(BiTNode)); (*T)->data = ch; g_p++; createBinTreeByPre(&((*T)->lch),*g_p); g_p++; createBinTreeByPre(&((*T)->rch),*g_p); } } //前序遍历 void preVisitTree(pBiTNode r) { if(r == NULL) { return ; } printf(" %c ",r->data); preVisitTree(r->lch); preVisitTree(r->rch); } //中序遍历 void midVistitTree(pBiTNode r) { if (r == NULL) { return ; } midVistitTree(r->lch); printf(" %c ",r->data); midVistitTree(r->rch); } //后序遍历 void nextVistitTree(pBiTNode r) { if (r == NULL) { return ; } nextVistitTree(r->lch); nextVistitTree(r->rch); printf(" %c ",r->data); } int _tmain(int argc, _TCHAR* argv[]) { pBiTNode root=NULL; createBinTreeByPre(&root,*g_p); printf("pre:"); preVisitTree(root); printf("\n"); printf("mid:"); midVistitTree(root); printf("\n"); printf("nxt:"); nextVistitTree(root); printf("\n"); getchar(); return 0; }