数据结构~12.树与二叉树

数据结构学习~12.树与二叉树

本文是上一篇文章的后续,详情点击该链接~

树的基本概念

       树是一种非线性的数据结构。要理解树的概念及其术语的含义,用一个例子说明是最好的方法。就比如下图就是一棵树,它是若干节点的集合。是由唯一的根(A)和若干互不相交的子树。就比如说,A,D,H,M,I,J这六个结点组成的树就是一颗子树组成的。其中,每一棵子树又是一棵树,也是由唯一的根结点和若干棵互不相交的子树组成的。由此而知,树的定义是递归的,也就是在树的定义中又用到了树的定义。要注意的是,树的结点数目可以为0,当为0时,这棵树称为一颗空树。

树的基本术语

结点:

       刚刚那棵树的A,B,C等都是结点,结点不仅包含数据元素,而且包含指向子树的分支。也就是说A的结点不仅包含数据元素A,而且包含三个指向子树的指针。

结点的度:

       结点拥有的子树个数或者分支的个数称为结点的度。就比如说A结点有三棵子树,所以A结点的度为3

树的度

       树中各结点度的最大值。比如说树的结点度最大为3(就像刚才那棵树的A结点),最小为0(就像是K,L,M等)

叶子结点

       叶子结点又叫做终端结点,指度为0的结点,就比如刚才那棵树K,L,F,G,M,I,J都是叶子结点

非终端结点

       非终端结点又叫做分支结点,指度不为0的结点,刚才那棵树除了叶子节点外,其他的都是非终端结点。除了根节点之外的非终端结点,也叫做内部结点。就像B,C,D,E,H结点都是内部结点

孩子

       结点的子树的根,就比如说刚才那棵树的B,C,D都属于A的孩子

双亲

       与孩子的定义对应,如B,C,D结点都是双亲A

兄弟

       同一个双亲的孩子之间互为兄弟。就比如说B,C,D就互为兄弟。因为他们都是A的孩子

祖先

       从根到某路径上的所有结点都是这个结点的祖先。比如说M的祖先是A,D,H。因为从A到M的路径是 A -> D -> H -> M

子孙

       以某结点为根的子树中所有结点都是该结点的子孙。就比如说B的子孙为E,F,K,L

层次与高度

       从根开始,根为第一层,根的孩子为第二层,根的孩子的孩子为第三层以此类推。而高度的话呢,其实就是树中结点的最大层次。就比如说刚刚那棵树最大层次是4层所以高度是4

堂兄弟

       双亲在同一层的结点互为堂兄弟。如G和H互为堂兄弟,因为G的双亲是C,H的双亲是D,C和D在同一层上。

有序树

       树中结点的子树从左到右都是有次序的,不能交换。这样的树叫做有序树

无序树

       树中结点的子树没有顺序,可以任意交换,这样的树叫做无序树

丰满树

       丰满树也就是理想平衡树,要求除最底层外,其他层都是满的。

森林

       若干棵互不相交的树的集合。例子中如果把A去掉,剩下的三棵子树互不相交。它们组成一个森林

树的存储结构

顺序存储结构

       树的顺序存储结构中最简单直观的是双亲存储结构,用整形一维数组即可实现。最简单的定义方法可以是int tree[maxsize],也就是用一个数组就可以存储一棵树的信息

       就比如说上面这张图,用数组的下标来表示树中的结点,然后我们用数组元素的内容来表示该结点的双亲结点。这样有了结点(下标)以及结点之间的关系(内容),就可以表示一棵树了。

       在这张图中,下标5上的内容为3,就是说5的双亲结点为3。下标1的内容为-1,就表示是根节点了~。这种定义主要就是当知道一个结点之后,就很容易找到双亲结点。

       注意:这里介绍的双亲存储结构是高度简化的形式,实际应用中肯定是不会这么做的。

链式存储结构

       树的链式存储最常用的有以下两种:

              孩子存储结构

              孩子兄弟存储结构

二叉树

二叉树的定义

       在理解了树的定义之后,二叉树就很好理解了。将一般的树满足

       每个结点最多只能有两颗子树,也就是说二叉树中结点的度只能为0、1、2。

       二叉树有左子树和右子树,并且不能颠倒。这样就得到二叉树了~

二叉树的五种形态

       空二叉树,只有根节点,只有左子树,只有右子树,既有左子树也有右子树

满二叉树与完全二叉树

       在一颗二叉树中,如果所有分支结点都有左孩子和右孩子结点。并且叶子结点都集中在二叉树最下面一层。而这样的二叉树称为满二叉树。约定编号从1开始,从上到下,从左到右进行

       如果对一颗深度为k,有n个结点的二叉树进行编号后,各结点的编号与深度为k的满二叉树中相同位置上的结点的编号均相同,那么这颗二叉树就是完全二叉树

图(a)为满二叉树,图(b)为完全二叉树。(作者字太难看,就用字母了==||)


二叉树的存储结构

顺序存储结构

       顺序存储结构就是用一个数组来存储一颗二叉树,这种存储方式最适合完全二叉树。如果用来存储一般的二叉树的话,就会浪费大量的空间。将完全二叉树的结点按照编号依次存入一个一维数组中,也就完成了一个二叉树的顺序存储。

链式存储结构

       顺序存储结构显然有一个很大的局限性,不便于存储任意形态的二叉树。观察二叉树的状态可以发现是一个根节点与两棵子树之间的关系。因此设计出了含有一个数据域和两个指针域的链式存储结构。

typedef struct BinaryNode {
	char data;		//数据域
	struct BinaryNode* left;	//指针域 左孩子
	struct BinaryNode* right;	//指针域 右孩子
}Tree;
二叉树以链式存储结构存储

二叉树的遍历算法

#include
#include
typedef struct BinaryNode {
	char data;		//数据域
	struct BinaryNode* left;	//指针域 左孩子
	struct BinaryNode* right;	//指针域 右孩子
}Tree;
//赋值
Tree* getTree(char data) {
	Tree* tree = (Tree*)malloc(sizeof(Tree));
	tree->data = data;
	tree->left = NULL;
	tree->right = NULL;
	return tree;
}
//先序遍历
void preOrder(Tree* root) {
	if (root != NULL) {
		printf("%c ", root->data);
		preOrder(root->left);
		preOrder(root->right);
	}
}
//中序遍历
void inOrder(Tree* root) {
	if (root != NULL) {
		inOrder(root->left);
		printf("%c ", root->data);
		inOrder(root->right);
	}
}
//后序遍历
void postOrder(Tree* root) {
	if (root != NULL) {
		postOrder(root->left);
		postOrder(root->right);
		printf("%c ", root->data);
	}
}
int main(int argc, char* argv[]) {
	Tree* tree = (Tree*)malloc(sizeof(Tree));
	tree = getTree('A');
	tree->left = getTree('B');
	tree->right = getTree('C');
	tree->left->left = getTree('D');
	tree->right->left = getTree('E');
	tree->right->right = getTree('F');
	//先序遍历
	printf("先序遍历:\t");
	preOrder(tree);
	//中序遍历
	printf("\n中序遍历:\t");
	inOrder(tree);
	//后序遍历
	printf("\n后序遍历:\t");
	postOrder(tree);
	return 0;
}

此树的结构

你可能感兴趣的:(数据结构)