坚持,做一件事不难,难的是,一直坚持做一件事!在这中间,肯定有这个那个的牵绊,但自己的目标要明确,一直努力。
// 数据结构_二叉查找树.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
typedef struct TWOTREE{
TWOTREE *p;
TWOTREE *left;
TWOTREE *right;
int key;
}TWOTREE,*PTWOTREE;
/*查找树是一种数据结构,它支持多种动态集合操作,包括SEARCH,
MINIMUM,MAXIMUN,PREDECESSOR,SUCCESSOR,INSERT,DELETE,它既可以用作字典,也可以用作优先队列
二叉查找树上执行的基本操作的时间和树的高度成正比,对于一颗含有N个结点的完全二叉树
这些操作的基本时间为lgN,如果树是含有N个结点的线性链,则这些操作的最坏情况运行时间为N*/
/*
算法导论中的二叉查找树插入的伪代码
TREE-INSERT(T,z)
1 y <- NIL
2 x <- root(T)
//3-8行,我们第一次初始化根结点的时候,其左右儿子结点和父结点都为NULL,插入第一个数时,只执行一次
//第二次执行时,根结点或左或右儿子结点肯定不为NULL,插入的结点除了跟结点比较,还可能跟插入的结点比较,前提是第二次结点
跟第一次结点一样,比根结点小,或者大。
3 while x != NIL
4 do y <- x
5 if key[z] < key[x]
6 then x <- left[x]
7 else x <- right[x]
这里的y有保存x结点的值,不管此时结点z的key值是小于y的key,还是大于y的key,z的父结点肯定是y.
8 p[z] <- y
9 if y = NIL 这里当为空树时,此时根结点也为NULL,直接将第一个值z当成根结点
10 then root[T] <- z
11 else if key[z] < key[y] 刚才只设置了,z的父结点,这里还要设置y的左右儿子结点,是左还是右,key值决定。
12 then left[y] <- z
13 else right[y] <- z
*/
int tree_insert(TWOTREE *root,TWOTREE *z){
PTWOTREE x = NULL,y = NULL;
x = root;
while(x != NULL){
y = x;
if( z->key < x->key){
x = x->left;
}
else{
x = x->right;
}
}
z->p = y;
if(NULL == y){
root = z;
}
else if(z->key < y->key){
y->left = z;
}
else{
y->right = z;
}
return 0;
}
/*二叉查找树,中序遍历伪代码
INORDER-TREE-WALK(x)
1 if x != NULL
2 then INORDER-TREE-WALK(left[x])
3 print key[x]
4 INORDER-TREE-WALK(right[x])
*/
int inorder_tree_walk(TWOTREE *x){
if(x != NULL){
inorder_tree_walk(x->left);
printf("%d ",x->key);
inorder_tree_walk(x->right);
}
return 0;
}
/*
查询二叉查找树
TREE-SEARCH(x,k)
1 if x=NIL or k = key[x]
2 then return x
3 if k < key[x]
4 then return TREE-SEARCH(left[x],k)
5 else return TREE-SEARCH(right[x],k)
*/
/*
ITERATIVE-TREE-SEARCH(x,k)
1 while x != NIL and k != key[x]
2 do if k < key[x]
3 then x <- left[x]
4 else x <- right[x]
5 return x
*/
TWOTREE *interative_tree_search(TWOTREE *x,int k){
while((NULL != x) &&(k != x->key)){
if (k < x->key){
x = x->left;
}
else{
x = x->right;
}
}
return x;
}
/*最小元素的寻找
TREE-MINIMUN(x)
1 while left[x] != NIL
2 do x <- left[x]
3 return x
*/
TWOTREE *tree_minimum(TWOTREE *x){
while(NULL != x->left){
x = x->left;
}
return x;
}
/*最大元素的寻找
TREE-MAXIMUM(x)
1 while right[x] != NIL
2 do x <- right[x]
3 return x
*/
TWOTREE *tree_maximum(TWOTREE *x){
while(NULL != x->right){
x = x->right;
}
return x;
}
/*
前趋和后继
给定一个二叉查找树结点,有时候要求找出中序遍历顺序下它的后继,如果所有的关键字都不相同
则某一结点的后继即具有大于key[x]中的关键字中最小者的那个结点,根据二叉查找树的结构,不用对关键字做任何比较,就
可以找到某个结点的后继
TREE-SUCCESSOR(x)
1 if right[x] != NIL 如果x结点的右子树不为空,x结点的后继就是右子树中的最左结点
2 then return TREE-MINIMUM(right[x])
3 y <- p[x]
4 while y != NIL and x = right[y] 为了找到,一个结点,它的左儿子是y的父结点
5 do x <- y
6 y <- p[y]
7 return y
*/
TWOTREE *tree_successor(TWOTREE *x){
PTWOTREE y = NULL;
if(x->right != NULL){
return tree_minimum(x->right);// x 的右子树的最左孩子就是x的后继
}
y = x->p;// x结点没有右子树,如果x是其父结点的左孩子,直接返回x的父结点
while((y != NULL) &&(x == y->right)){//如果x结点,是其父结点的右孩子,一直要找一个,其父结点是要找结点的左孩子。返回这个结点
x = y;
y = y->p;
}
return y;
}
/*
删除,将给定结点z从二叉查找树中删除的过程以指向z的指针为参数
并考虑三中情况
如果z没有子女,则修改其父结点p[z],使其左或右子女为NIL,如果结点z只有一个子女,则可以通过在其父结点间建立一条链
来删除z,最后如果结点z有两个子女,则先删除z的后继y(它没有左子女),再用y的内容来替代z的内容
TREE-DELETE(T,z)
1 if left[z] = NIL or right[z] = NIL
2 then y <- z
3 else y <- TREE-SUCCESSOR(z)
4 if left[z] != NIL
5 then x <- left[y]
6 else x <- right[y]
7 if x != NIL
8 then p[x] <- p[y]
9 if p[y] = NIL
10 then root[T] <- x
11 else if y = left[p[y]]
12 then left[p[y]] <- x
13 else right[p[y]] <- x
14 if y != z
15 then key[z] <- key[y]
16 copy y's satellite data inti z
17 return y
*/
TWOTREE *tree_delete(TWOTREE *root,TWOTREE *z){
PTWOTREE y = NULL,x = NULL;
// 如果待删除的结点,有一个孩子
if((z->left == NULL) || (z->right == NULL)){
y = z;
}
else{
// 如果结点有两个孩子,找到z的后继为y
y = tree_successor(z);
}
if(z->left != NULL){
// y可能是z的后继,或者y=z;
x = y->left;
}
else{
// y不可能是z的后继,因为z->left为NULL,此时x可以为NULL,或者不为NULL.
x = y->right;
}
if( x != NULL){
x ->p = y->p; //x 的父结点等于y的父结点,如果是后继并且后继有左孩子,就将后继左孩子的父结点等于后继的父结点
}
if(y->p == NULL){
root = x; // 父结点为NULL ,必定是根结点。
}
else if(y == y->p->left){//如果y是其父结点的左孩子
y->p->left = x; //就将y的父结点的左孩子设置成x
}
else{
y->p->right = x;//就将y的父结点的右孩子设置成x
}
if(y != z){// 如果z有两个孩子,就需要将z后继拷贝到z的位置。
z->key = y->key;
}
return y;
}
int main(int argc, char* argv[])
{
PTWOTREE root = NULL;
PTWOTREE z;
PTWOTREE ptemp;
int a[] = {12,5,2,9,18,15,19,13,17};
int i = 0;
root = (TWOTREE *)malloc(sizeof(PTWOTREE));
root->p = NULL;
root->key = a[0];
root->left = NULL;
root->right = NULL;
for(i = 1; i < 9;i++){
z = (TWOTREE *)malloc(sizeof(PTWOTREE));
z->key = a[i];
z->p = NULL;
z->left = NULL;
z->right = NULL;
tree_insert(root,z);
}
inorder_tree_walk(root);
ptemp = tree_delete(root,root->left);
printf("\n");
inorder_tree_walk(root);
ptemp = interative_tree_search(root,17);
ptemp = tree_minimum(root);
printf("\nminimum %d\n",ptemp->key);
ptemp = tree_maximum(root);
printf("maximun %d\n",ptemp->key);
ptemp = tree_maximum(root->right->left);
printf("houji %d",ptemp->key);
return 0;
}