C/C++实现树形结构之二叉树
树的概念
树形结构是一类非常重要的非线性数据结构,树中节点的位置具有明确的层次关系。并且结点之间有分支,非常类似于真正的树。而我们这里着重讲述的是二叉树。
二叉树是树形结构的一种重要的类型,在实际应用中有着非常重要的作用和意义。二叉树是n个节点的有限集合,他的每个节点至多只有两棵子树。当然也可以是空集。或者是由一个根节点及两棵互不相交的分别成为这个根的左子树和右子树的二叉树组成。
从以上概念中,我们可以看出,树的定义是递归的。根据这个定义我们也可以导出二叉树的五种形态(1)空二叉树 (2)仅有根节点 (3)只有左子树 (4)只有右子树 (5)既有左子树又有右子树。
二叉树的概念
性质1:
在二叉树的第i层上至多有2^(i-1)个节点
性质2:
深度为k的二叉树至多有2^k-1个结点(k>=1)
性质3:
对任何一棵二叉树T,若其终端结点数为n0,度数为2的结点数为n2,则n0=n2+1
性质四可以从前面的性质中推出。可以自己尝试下。
二叉树的逻辑结构
二叉树的逻辑结构为:一共三个域,其中一个指向它的左孩子的根结点,另一个指向它右孩子的根结点。数据域存储数据。
typedef struct node {
DataType data;
node* lchild, *rchild;
} BinTNode;
typedef BinTNode * BinTree;
根据广义表生成二叉树
在前面一篇文章中,我曾给大家介绍过广义表,广义表也是一种树形结构,你们可以把它看成是线性结构像非线性结构的过度。传送门:
这段代码是利用了广义表来建立一个树的。该算法稍微简单一些,但是要求用广义表表示二叉树的理解要深刻。它与普通的表示二叉树的广义表形式有些不同,因为他有左右子树之分。括号左边的结点是在左子树上,括号右边的结点是在右子树上。
算法中使用了一个指针数组来模拟栈的存储结点的双亲指针,根据读入广义表中的字符分四种不同情况来处理。
BinTNode* CreateTree(const char* str)
{
BinTNode* St[100];
BinTNode* p = NULL;
int top, k=0, j = 0;
top = -1;
char chr = str[j];
BinTNode* b = NULL;
while(chr != '\0')
{
switch (chr) {
case '(':top++; St[top] = p; k = 1; break;
case ')':top--; break;
case ',':k = 2; break;
default:
p = (BinTNode*)malloc(sizeof(BinTNode));
p->data = chr;
p->lchild = p->rchild = NULL;
if (b == NULL) b = p;
else {
switch (k) {
case 1:St[top]->lchild = p; break;
case 2:St[top]->rchild = p; break;
}
}
}
j++;
chr= str[j];
}
return b;
}
按完全二叉树的层次顺序依次输入结点信息建立二叉链表的算法
该算法的基本思想是:首先对一般的二叉树添加若干个虚结点,使其成为完全二叉树。然后依次的输入节点的信息。若输入的节点信息不是虚结点’@‘,则建立一个新结点。若为第一个结点,则为根节点。否则将新节点作为左孩子或者是右孩子链接到它的双亲结点上。如此重复,直到遇到结束符号’#‘
//按照完全二叉树的层次顺序建立二叉链表
BinTree CreateBinTree(BinTree bt)
{
BinTNode* Q[100];
BinTNode* s;
int front, rear;
char ch;
ch = getchar();
bt = NULL;
front = 1;
rear = 0;
while (ch != '#')
{
s = NULL;
if (ch!= '@')
{
s = (BinTNode*)malloc(sizeof(BinTNode));
s->data = ch;
s->lchild = s->rchild = NULL;
}
rear++;
Q[rear] = s;
if (rear == 1)bt = s;
else {
if (s != NULL && Q[front] != NULL)
{
if (rear % 2 == 0) { Q[front]->lchild = s; }
else Q[front]->rchild = s;
}
if (rear % 2 != 0)front++;
}
ch = getchar();
}
return bt;
}
递归实现的遍历算法
//前序遍历算法
void Preorder(BinTree bt)
{
if (bt != NULL)
{
printf("%c", bt->data);
Preorder(bt->lchild);
Preorder(bt->rchild);
}
}
//中序遍历算法
void Midorder(BinTree bt)
{
if (bt != NULL)
{
Midorder(bt->lchild);
printf("%c", bt->data);
Midorder(bt->rchild);
}
}
//后序遍历算法
void Postorder(BinTree bt)
{
if (bt != NULL)
{
Postorder(bt->lchild);
Postorder(bt->rchild);
printf("%c", bt->data);
}
}
非递归实现的遍历算法
void Inorder1(BinTree bt)
{
BinTNode* ST[100];
int top = 0;
ST[top] = bt;
do {
while (ST[top] != NULL) {
top = top + 1;
ST[top] = ST[top - 1]->lchild;
}
top = top - 1;
if (top >= 0)
{
printf("%c", ST[top]->data);
ST[top] = ST[top]->rchild;
}
} while (top != -1);
}