2.8 树
树是一种分层性数据结构。在一棵树里存储着一组项,每个项保存一个值,它可以有指针指向0个或多个元素,但只能被另一个项所指。树根是其中惟一的例外,没有其他项的指针指向它。
实际存在许多不同种类的树,它们表示各种复杂的结构。在这里,我们使用二分检索树来说明树的原理。二分检索树的每个结点带有两个子结点指针,left和right,它们分别指向对应的子结点。而对于一个特定的节点,其左节点中一般储存着较小的值;而右节点中一般储存着较大的值。而这种存在形式则十分利于检索。
我们同样使用Nameval型的结构体来作为一个节点。
typedef struct Nameval Nameval;
struct Nameval
{
char *name;
int value;
Nameval *left;/*smaller value*/
Nameval *right;/*bigger value*/
};
由于树的许多结点包含多个指向其他元素的指针,所以,很多在表或者数组结构中需要O(n)时间的操作,在树中只需要O(log(n))时间。结点存在多个指针能减少为寻找一个结点所需要访问的结点个数,从而降低操作的复杂性。
对于构建一个新的二叉树,我们一般在递归向下,根据情况确定左节点或者右节点,直到找到节点所处的正确位置。这个新的节点应该正确的初始化为一个名字、一个数值和两个空指针。
对于构建一个新的叶子节点,一种直观的感觉就是顺着现有的枝杈来到末端,构建好之后仔原路返回。因此,递归就是一个很好的实现方式。
则代码的实现则为:
#include "stdafx.h"
#include "stdlib.h"
#include "string.h"
#include <iostream>
using namespace std;
typedef struct Nameval Nameval;
struct Nameval
{
char *name;
int value;
Nameval *left;
Nameval *right;
};
/*插入节点*/
/*treep定义为搜索开始的节点*/
/*treep->left和treep->right都为指向下一个节点(叶子)的头地址*/
Nameval *insert(Nameval *treep, Nameval *newp)
{
int cmp;
if (treep == NULL)
{
/*插入节点*/
return newp;
}
cmp = strcmp(newp->name, treep->name);
if (cmp == 0)
{
printf("The name '%s' has already been created", newp->name);
}
/*搜索插入位置*/
else if (cmp < 0)
{
treep->left = insert(treep->left, newp);
}
else
{
treep->right = insert(treep->right, newp);
}
/*原路返回*/
return treep;
}
Nameval *lookup(Nameval *treep, char *name)
{
int cmp;
if (treep == NULL)
{
return NULL;
}
cmp = strcmp(name, treep->name);
if (cmp == 0)
{
return treep;
}
else if (cmp < 0)
{
/*注意这里的return*/
/*递归时,返回值的数量要与递归函数相匹配*/
return lookup(treep->left, name);
}
else
{
return lookup(treep->right, name);
}
}
void initial(Nameval *list, char *name, int value)
{
list->left = NULL;
list->right = NULL;
list->value = value;
list->name = name;
}
int main()
{
Nameval *list_1 = NULL, *list_2 = NULL, *test = NULL;
list_1 = (Nameval *)malloc(sizeof(Nameval));
list_2 = (Nameval *)malloc(sizeof(Nameval));
initial(list_1, "abc", 1);
initial(list_2, "def", 2);
/*验证是否函数调用成功*/
cout << list_1->right << endl;
list_2 = insert(list_1, list_2);
cout << list_1->right << endl;
test = lookup(list_1, "abc");
cout << test->name << endl;
return 0;
}