本文原始地址:C算法学习笔记(2)-二叉查找树
查找操作
若根结点的关键字值等于查找的关键字,成功。
否则,若小于根结点的关键字值,递归查左子树。
若大于根结点的关键字值,递归查右子树。
若子树为空,查找不成功。
/* //二叉树查找算法 //T 二叉树 //x 要查找的值 */ BiTree BSTSearch(BiTree T,int x) { BiTreeNode *p; if (T != NULL) { p = T; while (p != NULL) { if (p->data == x)//如果该结点就是我们想要的 { return p; }else if(x > p->data)//如果查找的值是该结点右子树 { p = p->rchild; }else//如果查找的值是该结点左子树 { p = p->lchild; } } } return NULL; }
插入操作
首先执行查找算法,找出被插结点的父亲结点。
判断被插结点是其父亲结点的左、右儿子。将被插结点作为叶子结点插入。
若二叉树为空。则首先单独生成根结点。
注意:新插入的结点总是叶子结点。
/* //二叉树插入操作 //T 二叉树 //x 要插入的值 */ int BSTInsert(BiTree *T,int x) { BiTreeNode *p = NULL;//把x组装成一个只有根结点的树 BiTreeNode *cur = NULL;//纪录当前遍历的结点 BiTreeNode *parent = NULL;//纪录上一次遍历的结点,最后一个值为我们需要插入的结点位置 cur = *T; while (cur != NULL) { if (cur->data == x)//插入操作如果数值已存在,插入失败 { return 0; } parent = cur;//将到该结点子树遍历,纪录下该结点,该循环最终输出值 if (x < cur->data)//到该结点左子树继续遍历 { cur = cur->lchild; }else//到该结点右子树继续遍历 { cur = cur->rchild; } } //申请内存空间 p = (BiTreeNode *)malloc(sizeof(BiTreeNode)); if (!p)//内存空间申请失败,内存不够用了,终止程序 { exit(-1); } //初始化p结点 p->data = x; p->lchild = NULL; p->rchild = NULL; if (!parent) { *T = p;//这本来就是棵空树,p将会作为根结点 }else if(x < parent->data) { parent->lchild = p; }else { parent->rchild = p; } return 1;//插入成功 }
删除操作
1.若*p结点为叶子结点,即PL(左子树)和PR(右子树)均为空树。由于删去叶子结点不破坏整棵树的结构,则只需修改其双亲结点的指针即可。
2.若*p结点只有左子树PL或右子树PR,此时只要令PL或PR直接成为其双亲结点*f的左子树(当*p是左子树)或右子树(当*p是右子树)即可,作此修改也不破坏二叉排序树的特性。
3.若*p结点的左子树和右子树均不空。在删去*p之后,为保持其它元素之间的相对位置不变,可按中序遍历保持有序进行调整,可以有两种做法:
其一是令*p的左子树为*f的左/右(依*p是*f的左子树还是右子树而定)子树,*s为*p左子树的最右下的结点,而*p的右子树为*s的右子树;
其二是令*p的直接前驱(或直接后继)替代*p,然后再从二叉排序树中删去它的直接前驱(或直接后继)-即让*f的左子树(如果有的话)成为*p左子树的最左下结点(如果有的话),再让*f成为*p的左右结点的父结点。
/* //删除结点 //删除的结点s //原则:保持二叉树性质不变-根结点的值大于左子树的值小于右子树的值... */ void DeleteNode(BiTree *s) { if (!s) return; BiTreeNode *q = NULL;//中间量,纪录旧的的s结点数据 BiTreeNode *x = NULL; BiTreeNode *y = NULL; if(!(*s)->rchild)//如果右子树不存在 { q = (*s); (*s) = (*s)->lchild; free(q); }else if(!(*s)->lchild)//如果左子树不存在 { q = (*s); (*s) = (*s)->rchild; }else//如果左右都存在的话,令*p的直接前驱(或直接后继)替代*p,然后再从二叉排序树中删去它的直接前驱(或直接后继)-即让*f的左子树(如果有的话)成为*p左子树的最左下结点(如果有的话),再让*f成为*p的左右结点的父结点。 { x = (*s); y = (*s)->lchild; while (y->rchild)//查找s的直接前驱结点,y为s的直接前驱结点,x为y的双亲结点 { x = y; y = y->lchild; } (*s)->data = y->data;//结点s被y取代 if (x != (*s))//如果结点s的左孩子结点不存在右子树 { x->rchild = y->lchild;//使y的左子树成为x的右子树 }else { x->lchild = y->lchild; } free(y); } } /* //在二叉树中查找关键字为x的结点,并删除,删除成功返回1,否则返回0 //T 二叉树 //x 关键字 */ int BSTDelete(BiTree *T,int x) { if (!*T) return 0; if (x == (*T)->data) { DeleteNode(T); }else if (x < (*T)->data) { BSTDelete(&(*T)->lchild,x); }else { BSTDelete(&(*T)->rchild,x); } return 1; }
附:中序遍历
//中序遍历 void InOrderTraverse(BiTree T) { if (T) { InOrderTraverse(T->lchild); printf("%4d",T->data); InOrderTraverse(T->rchild); } }
视频地址:BST:二叉查找树