树是由n(n >= 0)个结点组成的有限集合,如果n = 0, 则称为空树,如果n > 0,则
一棵二叉树是结点的一个有限集合,该集合或者为空,或者由一个根结点加上两棵称之为左子树和右子树的、两个互不相交的二叉树组成。
数据元素之间的关系有两种不同的表示方法:顺序映象和非顺序映象,并由此得到两种不同的存储结构:顺序存储结构和链式存储结构。
数据的存储结构是指数据的逻辑结构在计算机中的表示。
这种表示形式,结点直接有一种关系:
下图分别是二叉树的树型逻辑图,二叉链表表示图,三叉链表表示图
二叉链表方式,没有parent的二叉树
typedef int ElemType;
typedef struct BtNode
{
ElemType data;
struct BtNode* leftchild;
struct BtNode* rightchild;
}BtNode, *BinaryTree;
所谓树的遍历,就是按某种次序访问树中的结点,要求每个结点访问一次且仅访问一次。
设访问根结点记作V; 遍历根的左子树记作L;遍历根的右子树记作 R;
遍历规则 | 遍历方式 |
---|---|
前序遍历(先序遍历) | VLR |
中序遍历 | LVR |
后序遍历 | LRV |
void PreOrder(BtNode* root)
{
if (root != NULL)
{
cout << root->data << " ";
PreOrder(root->leftchild);
PreOrder(root->rightchild);
}
}
void InOrder(BtNode* root)
{
if (root != NULL)
{
InOrder(root->leftchild);
cout << root->data << " ";
InOrder(root->rightchild);
}
}
void PastOrder(BtNode* root)
{
if (root != NULL)
{
PastOrder(root->leftchild);
PastOrder(root->rightchild);
cout << root->data << " ";
}
}
BtNode* Buynode()
{
BtNode* s = (BtNode*)malloc(sizeof(BtNode));
if (NULL == s) exit(1);
memset(s, 0, sizeof(BtNode));
return s;
}
// ABC##DE##F##G#H##
BtNode* CBTree1()
{
BtNode* s = NULL;
ElemType elem;
cin >> elem;
if (elem != '#')
{
s = Buynode();
s->data = elem;
s->leftchild = CBTree1();
s->rightchild = CBTree1();
}
return s;
}
这个过程实际上也是运用了分治策略,不停的划分,直至规模达到最小。
图解:
通过中序遍历确定出先序遍历第一个元素的位置,那么中序遍历中A的左边就是A的左子树,有五个元素,所以先序遍历也要划分出五个元素作为左子树;剩下的G/H 为右子树。
在划分出左子树后,拿左子树继续划分,从中序遍历中找到先序遍历的元素B的位置,那么左边就是B的左子树,按照元素个数,先序遍历B的右边划分出相同元素个数作为左子树,剩下的作为右子树。
int FindIs(const char* is, int n, char ch)
{
int pos = -1;
for (int i = 0; i < n; ++i)
{
if (is[i] == ch)
{
pos = i;
break;
}
}
return pos;
}
BtNode* CreatePI(const char* ps, const char* is, int n)
{
BtNode* s = NULL;
if (n > 0)
{
s = Buynode();
s->data = ps[0];
int pos = FindIs(is, n, ps[0]);
if (pos == -1) exit(1);
s->leftchild = CreatePI(ps + 1, is, pos);
s->rightchild = CreatePI(ps + 1 + pos, is + 1 + pos, n - pos - 1);
}
return s;
}
BtNode* CreateBinaryTreePI(const char* ps, const char* is, int n)
{
if (ps == NULL || is == NULL || n < 0) return NULL;
else
return CreatePI(ps, is, n);
}
测试用例:
int main(void)
{
char ps[] = { "ABCDEFGH" };
char is[] = { "CBEDFAGH" };
char ls[] = { "CEFDBHGA" };
int n = strlen(ps);
BinaryTree root = NULL;
root = CreateBinaryTreePI(ps, is, n);
PreOrder(root);
cout << endl;
InOrder(root);
cout << endl;
PastOrder(root);
cout << endl;
return 0;
}
和上述规则一样,分治策略划分
int FindIs(const char* is, int n, char ch)
{
int pos = -1;
for (int i = 0; i < n; ++i)
{
if (is[i] == ch)
{
pos = i;
break;
}
}
return pos;
}
BtNode* CreateIL(const char* is, const char* ls, int n)
{
BtNode* s = NULL;
if (n > 0)
{
s = Buynode();
s->data = ls[n - 1];
int pos = FindIs(is, n, ls[n - 1]);
if (-1 == pos) exit(1);
s->leftchild = CreateIL(is, ls, pos);
s->rightchild = CreateIL(is + pos + 1, ls + pos, n - pos - 1);
}
return s;
}
BtNode* CreateBinaryTreeIL(const char* is, const char* ls, int n)
{
if (is == NULL || ls == NULL || n <= 0) return NULL;
else
return CreateIL(is, ls, n);
}
测试用例:
int main(void)
{
char ps[] = { "ABCDEFGH" };
char is[] = { "CBEDFAGH" };
char ls[] = { "CEFDBHGA" };
int n = strlen(ps);
BinaryTree root = NULL;
root = CreateBinaryTreeIL(is, ls, n);
PreOrder(root);
cout << endl;
InOrder(root);
cout << endl;
PastOrder(root);
cout << endl;
return 0;
}