二叉搜索树(BST)的基本操作

来源:互联网 发布:自己动手写网络爬虫pdf 编辑:程序博客网 时间:2024/05/16 19:25

二叉搜索树(Binary Search Tree)是一种有如下特征的二叉树:

a,若它的左子树不为空,则左子树上所有结点的值均小于对应根结点的值;

b,若它的右子树不为空,则右子树上所有结点的值均大于对应根结点的值;

c,左子树和右子树分别构成一个二叉搜索树。

二叉树搜索树的查找、插入、删除等操作的复杂度为O (logN)。

结点结构定义为:

typedef struct node {int data;structnode *left;struct  node *right;}Node;

创建结点函数定义为:

Node *new_node(int data){Node *node = (Node *)malloc(sizeof(Node));if(node == NULL){errno = ERR_MAL_MEMORY;print_error("new_node()");return NULL;}node->data = data;node->left = NULL;node->right = NULL;return node;}

1 查找

根据根结点与左右结点的相对位置,二叉树的查找分前序、中序和后序三种情况。一般的,中序查找能够得到一组从小到大的排序数据。

若结点值等于搜索值,返回该结点;若结点值大于搜索值,根据BST的构造原则,搜索该结点的左子树,反之,搜索右子树。

中序遍历如下:

a,递归方式

Node* search_node(Node *root, int data){Node *node = root;if(node == NULL)return NULL;if(node->data == data){printf("Find out!\nValue = %d, Mem = %p\n", data, &(node->data));return node;}else{if(node->data > data)return search_node(node->left, data);elsereturn search_node(node->right, data);}}

b,非递归方式

Node *search_node_nonrecursive(Node *root, int data){Node *node = root;while(node){if(node->data == data){printf("Find out!\nValue = %d, Mem = %p\n", data, &(node->data));return node;}else{if(node->data > data)node = node->left;elsenode = node->right;}}printf("\nCannot find %d.\n", data);return NULL;}


2,插入

将结点插入BST里时,只需将该结点插入到符合规则的合适位置,即修改相对应的根结点指针,再将两个子树赋值为NULL。其他的结点不用更改。

根据BST的构造原理,先搜索结点的左子树找到合适的位置,若不满足,再搜索右子树找到合适的位置,最后创建新结点。

a,递归方式

Node *insert_node(Node *root, int data){Node *node = root;if(node == NULL)return new_node(data);else{if(node->data > data)node->left = insert_node(node->left, data);else{node->right = insert_node(node->right, data);}return node;}}
b,非递归方式

Node *insert_node_nonrecursive(Node *root, int data){Node *node = root;Node *pnode = NULL;if(node == NULL)return new_node(data);while(node){pnode = node;if(node->data > data){node = node->left;if(node == NULL)pnode->left = new_node(data);}else{node = node->right;if(node == NULL)pnode->right = new_node(data);}}return root;}

3 ,删除

删除结点操作根据待删结点的子树分为三种情况,即无子树,含有单子树和含有双子树。在进行相关的删除操作之前,通过查找定位待删除的结点。

若无法定位待删除的结点,返回原树根结点。记待删除结点为child,其父结点为parent。

a,无子树

将父结点对应的子树置NULL;若该结点为跟结点,说明该树只有一个结点,即根结点,将根结点置为NULL;

b,单子树

将该结点的单一子树连接至结点父结点对应的子树,释放结点。

c,双子树

由于待删除的结点有双子树,因此必须在该结点的所有子树中选取一个结点来代替该结点的位置。选取替代结点有两种选择,即选取该结点左子树的最右端

的结点或者选取该结点右子树的最左端。一般取前者方式。在定位该结点后,操作和单子树相似。

删除代码如下:

Node *delete_node(Node *root, int data){Node *tree = root;Node *parent, *child;parent = NULL;child = NULL;while(tree){if(tree->data == data){child = tree;break;}else if(tree->data > data){parent = tree;tree = tree->left;}else{parent = tree;tree = tree->right;}}if(!child){printf("cannot find target node.\n");return root;}// child != NULLif((child->left == NULL) && (child->right == NULL)) // leaf node{if(parent == NULL) // root node{root == NULL;//return root;}else if(child == parent->left){parent->left = NULL;//return root;}else{parent->right = NULL;//return root;}}else if(!(child->left && child->right))  // has one child node{if(child->left){if(parent == NULL){root = child->left;//return root;}else{parent->left = child->left;//return root;}}if(child->right){if(parent == NULL){root = child->right;//return root;}else{parent->right = child->right;//return root;}}}else  // has two children nodes// find the max node of the deleted note, according to the rightmost of deleted node's left tree {Node *pMax = child->left;Node *pMaxParent = NULL;while(pMax->right){pMaxParent = pMax;pMax = pMax->right; // stored the right child value}if(pMax == child->left) // deleted note has one generation, as pMaxParent=NULL{pMax->right = child->right;}else // deleted note has more than one generations, as pMaxParent=NULL{ pMaxParent->right = pMax->left;pMax->left = child->left;pMax->right = child->right;}if(parent == NULL){root = pMax;}else if(parent->left == child)parent->left = pMax;elseparent->right = pMax;}free(child);return root;}







原创粉丝点击