【发布时间】:2017-01-10 11:58:30
【问题描述】:
使用给定的 BST 表示,
/****************tree.h ***********************/
typedef void* (*ProcessItem)(void *, void *);
/**************** BSTNode.c ************************/
typedef struct BinarySearchTreeNode{
void *key;
void *value;
bool visit; // For traversals
struct BinarySearchTreeNode *parent;
struct BinarySearchTreeNode *left;
struct BinarySearchTreeNode *right;
}Node;
typedef struct Tree{ //BST
Node *root;
int size;
}Tree;
static void visitFunc(ProcessItem, Node *);
作为学习的一部分,下面是详细的算法(在 C cmets 中)和为三个 DFS 遍历编写的相应代码。
预购遍历
/*
Pre-order traversal of BST and Binary tree: Node -> Left -> Right
0) Assuming node pointer is pointing to root node, which is, not NULL.
1) Visit node, if not visited
2) From that node,
If left sub-tree exists, and
If root node of that left sub-tree never visted,
then traverse to root node of left sub-tree.
Go to step 1 and continue until a node (that has visted root of left sub-tree) or (that has no left sub-tree exists)
3) From that node,
If right sub-tree exists, and
It root node of right sub-tree not visited,
then traverse to root node of right sub-tree.
Go to step 1 and continue, until a node (that has visited root of right sub-tree) or (that has no right sub-tree exists).
4) We reach this step, because,
Either left/right sub-tree exist but visited
or
left and right sub trees does not exist
Reach parent node and go to step-1 for applying pre-order traversal on that node
*/
static void preOrderTraverse(Node *n, ProcessItem action){
if (n == NULL){
return; // if tree is empty, then go back
}
Node *root = n; // |Step-0
while(root != NULL){
if(root->visit == false){
visitFunc(action, root); // |Step-1: Visit node, if not visited
}
if(root->left != NULL && // |Step-2: if left sub-tree exists, and
(root->left->visit == false) ){ // |Step-2: If root node of that left sub-tree's never visted,
root = root->left; // |Step-2: then traverse to root node of left sub-tree.
continue; // |Step-2: Go-to step 1
}
if(root->right != NULL && // |Step-3: if right sub-tree exists,
(root->right->visit == false) ){ // |Step-3: If root node of right sub-tree not visited,
root= root->right; // |Step-3: then traverse to root node of right sub-tree.
continue; // |Step-3: Go-to step 1
}
/*
If the instruction pointer points to below insruction, then that means,
Either left/right sub-tree exist but visited
or
left and right sub trees are empty
What can be done now?
Go to parent's tree root node and apply preOrderTraversal
*/
root = root->parent; // |Step-4 Reach parent node.
}
}
后序遍历
/*
Algorithm: Post-order traversal of BST and Binary tree: Left -> Right -> Node
0) Assuming node pointer is pointing to root node, which is, not NULL.
1) From that node,
If left sub-tree exists, and
If root node of that left sub-tree never visted,
then traverse to root node of left sub-tree.
Repeat step 1 until a node (that has visted root of left sub-tree) or (that has no left sub-tree exists)
2) From that node,
If right sub-tree exists, and
If root node of that right sub-tree never visted,
then traverse to root node of right sub-tree.
Go to step 1 and continue until a node (that has visited root of right sub-tree) or (that has no right sub-tree exists)
3) Visit that node, if not visited
4) We reach this step, because,
Either left/right sub-tree exist but all visited
or
left and right sub trees does not exist
Reach parent node and go to step-1 for applying post-order traversal on that node
*/
static void postOrderTraverse(Node *n, ProcessItem action){
if (n == NULL){
return; // if tree is empty, then go back
}
Node *root = n; // |Step-0
while(root !=NULL){
while(root->left != NULL && // |Step-1: If left sub-tree exists, and
(root->left->visit == false)){ // |Step-1: If root node of that left sub-tree never visted,
root=root->left; // |Step-1: then traverse to root node of left sub-tree.
}
if(root->right != NULL && // |Step-2: If right sub-tree exists, and
(root->right->visit == false)){ // |Step-2: If root node of that right sub-tree never visted,
root=root->right; // |Step-2: then traverse to root node of right sub-tree.
continue;
}
visitFunc(action, root); // |Step-3: Visit node, if not visited
/*
If the instruction pointer points to below insruction, then that means,
Either left/right sub-tree exist but all visited
or
left and right sub trees are empty
What can be done now?
Go to parent's tree root node and apply postOrderTraversal
*/
root = root->parent; // |Step-4: Reach parent node.
}
}
中序遍历
/*
Algorithm: In-order traversal of BST and Binary tree: Left -> Node -> Right
0) Assuming node pointer is pointing to root node, which is, not NULL.
1) From that node,
If left sub-tree exists, and
If root node of left subtree is never visted,
then traverse to root node of left sub-tree.
Repeat step1 until a node (that has visited root of left sub-tree) or (has no left sub-tree exists)
2) Visit that node, if not visited.
3) From that node,
If right sub-tree exists,
If root node of right sub-tree never visited,
then traverse to root node of right sub-tree
Goto step-1 and continue until a node (that has visited root of right sub-tree) or (has no right sub-tree exists).
4) We reach this step, because,
Either left/right sub-tree exists but visited
or
Either left/right sub-tree does not exist.
What can be done now?
Reach parent node and go to step-1 for applying In-order traversal on that node.
*/
static void inOrderTraverse(Node *n, ProcessItem action){
if (n == NULL){
return; // if tree is empty, then go back
}
Node *root = n; // |Step-0
while(root != NULL){
while(root->left != NULL && // |Step-1: If left sub-tree exists, and
(root->left->visit == false) ){ // |Step-1: If root node of left subtree is never visted,
root = root->left; // |Step-1: then traverse to root node of right sub-tree
}
if(root->visit == false){
visitFunc(action, root); // |Step-2: Visit node, if not visited.
}
if(root->right != NULL && // |Step-3: If right sub-tree exists, and
(root->right->visit == false) ){ // |Step-3: If root node of right sub-tree never visited,
root = root ->right; // |Step-3: then traverse to root node of right sub-tree
continue; // |Step-3: Go to step 1
}
/*
If instruction pointer reaches below instruction, then,
Either left/right sub-tree exists but all visited
or
Either left/right sub-tree does not exist.
*/
root = root->parent; // |Step-4: Reach parent node
}
}
其中visitFunc 在BSTNode.c 中定义,processItem 来自用户,
static void visitFunc(ProcessItem processItem, Node *node){
if(node->visit == TRUE){
return;
}
node->visit=true;
processItem(node->key, node->value);
return;
}
背景:
很明显,以上 DFS 算法都可以在线获得。但是,根据我的学习,这些算法所需的细节水平缺失。我认为,上述算法(在 C cmets 中)已经涵盖了这些缺乏细节。
强调提到的算法(在 C cmets 中)和使用parent 指针而不是显式堆栈的相应遍历代码,
我的问题:
1) 您是否发现所有三个遍历的 4 步算法和代码存在逻辑缺陷?
2) 上述代码中,访问节点前是否需要条件检查?
注意:遍历算法的初学者
【问题讨论】:
-
我看到一个编译时错误,因为
VisitFunc是一种类型。 -
是的,它是一种类型。你可以看到上面的typedef。我没有包含
visitFunc的定义。 -
并将其设为小写不会做任何事情,因为您将参数作为
action传递。您是否至少编译过一次? -
@StoryTeller 抱歉,
ProcessItem输入的不是visitFunc更新代码 -
这些函数要求在遍历树之前重置
visit字段。如果不通过遍历,您将如何做到这一点?
标签: c data-structures binary-search-tree tree-traversal