1 平衡二叉树的插入
关于平衡二叉树的定义什么的,就不再多说。直接说说各种功能的c语言实现。 首先插入的时候需要进行旋转以保证树始终保持平衡。而旋转的类型有四种:L-L型旋转,L-R型旋转,R-L型旋转,R-R型旋转。其中L-L型和R-R型只需要进行一次基本旋转操作就可以调整平衡;另外两种需要进行两次方向相反的旋转操作,才能达到目标。四种旋转类型如下:
然后定义两种基本的旋转操作:右旋(顺时针旋转)、左旋(逆时针旋转)。以上图中L-L型为例说明右旋操作。此时应该将节点10右旋,则以节点10的左孩子为轴,将节点10顺时针旋转使其成为其左孩子(节点5)的右孩子。同理,左旋操作应该以当前节点的右孩子为轴,逆时针旋转,使其成为其右孩子的左孩子。下面是两种基本选装操作的函数实现。
//定义节点结构 typedef struct Node { dataType keyValue; //数据 int BalanceFactor; //平衡因子 struct Node *leftChild, *rightChild; }*PNode; //右旋 顺时针旋转 void R_Rotate(PNode* node) { PNode tmp = (*node)->leftChild; (*node)->leftChild = tmp->rightChild; tmp->rightChild = (*node); (*node) = tmp; } //左旋,逆时针旋转 void L_Rotate(PNode* node) { PNode tmp = (*node)->rightChild; (*node)->rightChild = tmp->leftChild; tmp->leftChild = (*node); (*node) = tmp; }
四种类型的调整过程为,L-L型:将节点10右旋即可;L-R型:先将节点3左旋。调整为L-L型,再将节点10右旋;R-R型:将节点10左旋即可;R-L型:先将节点20右旋,调整为R-R型,再将节点10左旋即可。整个插入过程就是根据插入后的情况不断进行调整。
具体实现过程:
#include "stdafx.h" #include<stdio.h> #include<stdlib.h> #include<stack> #include<queue> using namespace std; typedef int dataType; #define EH 0 //左右子树一样高 #define LH 1 //左子树比右子树高 #define RH -1 //右子树比左子树高 //定义节点结构 typedef struct Node { dataType keyValue; //数据 int BalanceFactor; //平衡因子 struct Node *leftChild, *rightChild; }*PNode; //为新建一个节点 PNode createNode(dataType keyValue) { PNode newNode = (PNode)malloc(sizeof(Node)); newNode->keyValue = keyValue; newNode->BalanceFactor = EH; newNode->leftChild = NULL; newNode->rightChild = NULL; return newNode; } //右旋 顺时针旋转 void R_Rotate(PNode* node) { PNode tmp = (*node)->leftChild; (*node)->leftChild = tmp->rightChild; tmp->rightChild = (*node); (*node) = tmp; } //左旋,逆时针旋转 void L_Rotate(PNode* node) { PNode tmp = (*node)->rightChild; (*node)->rightChild = tmp->leftChild; tmp->leftChild = (*node); (*node) = tmp; } //左边失衡调整 void leftBalance(PNode* node) { PNode leftchild = (*node)->leftChild; PNode tmpRightChild = NULL; switch (leftchild->BalanceFactor) { case LH: //LL型失衡 (*node)->BalanceFactor = leftchild->BalanceFactor = EH; R_Rotate(node); break; case RH: //LR型失衡 tmpRightChild = leftchild->rightChild; switch (tmpRightChild->BalanceFactor) { case LH: (*node)->BalanceFactor = RH; leftchild->BalanceFactor = EH; break; case EH: (*node)->BalanceFactor = leftchild->BalanceFactor = EH; break; case RH: (*node)->BalanceFactor = EH; leftchild->BalanceFactor = LH; break; } tmpRightChild->BalanceFactor = EH; L_Rotate(&(*node)->leftChild); R_Rotate(node); break; } } //右边失衡调整 void rightBalance(PNode* node) { PNode rightchild = (*node)->rightChild; PNode tmpChild = NULL; switch (rightchild->BalanceFactor) { case RH: //RR型失衡 (*node)->BalanceFactor = rightchild->BalanceFactor = EH; L_Rotate(node); break; case LH: //RL型失衡 tmpChild = rightchild->leftChild; switch (tmpChild->BalanceFactor) { case LH: (*node)->BalanceFactor = EH; rightchild->BalanceFactor = RH; break; case EH: (*node)->BalanceFactor = rightchild->BalanceFactor = EH; break; case RH: (*node)->BalanceFactor = EH; rightchild->BalanceFactor = LH; break; } tmpChild->BalanceFactor = EH; R_Rotate(&(*node)->rightChild); L_Rotate(node); break; } } //插入新值,higher用于判定是否需要调整平衡因子 int InsertKeyValue(PNode* node, dataType keyValue,bool* higher) { if ((*node) == NULL) { //树中不包含此键值,则新建一个节点, (*node) = createNode(keyValue); *higher=true; } else if ((*node)->keyValue == keyValue) { //树中已经包含此键值,则不需要插入 *higher = false; return 0; } else if (keyValue < (*node)->keyValue) { //插入到左子树中 if (!InsertKeyValue(&(*node)->leftChild, keyValue, higher)) //如果左子树中存在该节点 return 0; if (*higher) { switch ((*node)->BalanceFactor) { case LH: leftBalance(node); *higher = false; break; case RH: (*node)->BalanceFactor = EH; *higher = false; break; case EH: (*node)->BalanceFactor = LH; *higher = true; break; } } } else { if (!InsertKeyValue(&(*node)->rightChild, keyValue,higher)) //如果右子树中存在该节点 return 0; if (*higher) { switch ((*node)->BalanceFactor) { case LH: (*node)->BalanceFactor = EH; *higher = false; break; case RH: rightBalance(node); *higher = false; break; case EH: (*node)->BalanceFactor = RH; *higher = true; break; } } } return 1; } int main() { int i, dataArr[] = { 1,23,45,34,98,9,4,35,23,36,37,90,85,80 }; PNode treeRoot = NULL; bool heigher; for (i = 0; i < 14; i++) { InsertKeyValue(&treeRoot, dataArr[i],&heigher); printfTree(treeRoot); printf("\n\n"); } return 0; }
2 平衡二叉树的遍历
平衡二叉树的遍历一般分为四种:先序、中序、后序和按层次遍历,每种遍历方法都有递归的和非递归的实现方法。
先实现一种按关系遍历的方法,用于检验上面二叉树的构造是否正确吧。
//按关系输出,便于检验数的构造是否正确 void printfTree(PNode root) { if (root) { if (root->leftChild) { printf("%d is %d's left child\n", root->leftChild->keyValue, root->keyValue); printfTree(root->leftChild); } if (root->rightChild) { printf("%d is %d's right child\n", root->rightChild->keyValue, root->keyValue); printfTree(root->rightChild); } } }
2.1 中序遍历
中序遍历的递归和非递归实现。所谓中序遍历就是对每个节点的输出顺序都是:左,中,右。递归方法实现很简单:
//中序--递归 void InorderTra(PNode root) { if (root) { InorderTra(root->leftChild); printf("%d\t", root->keyValue); InorderTra(root->rightChild); } }
中序非递归的实现需要利用一个栈。首选需要找到整棵树最左边的节点,并将查过过程中路径上的节点都源栈中,然后,去栈顶元素,输出值,在将其右子树的左节点压入栈。。。。直到栈为空。
//中序--非递归 void InorderTra2(PNode root) { if (!root) { printf("树为空!\n"); } stack<PNode> myStack; while (root|| !myStack.empty()) { //找到最左边的节点,并将路径上的几点压入栈中 while (root) { myStack.push(root); root = root->leftChild; } root = myStack.top(); //取栈顶的值 myStack.pop(); //从栈中删除 printf("%d\t", root->keyValue); root=root->rightChild; } printf("\n"); }
2.2 先序遍历
先序遍历,对每个节点的输出顺序都是:中,左,右。递归实现。
void PreOrderTra(PNode root) { if (root != NULL) { printf("%d\t", root->keyValue); PreOrderTra(root->leftChild); PreOrderTra(root->rightChild); } }
非递归实现。
//前序--非递归 void PreOrderTra2(PNode root) { if (!root) { printf("树为空!\n"); } stack<PNode> myStack; while (root || !myStack.empty()) { while (root) { myStack.push(root); printf("%d\t", root->keyValue); root = root->leftChild; } root = myStack.top(); myStack.pop(); root = root->rightChild; } printf("\n"); }
2.3 后序遍历
对每个节点的输出顺序都是:左,右,中。递归实现
//后序--递归 void PostOrderTra(PNode root) { if (root) { PostOrderTra(root->leftChild); PostOrderTra(root->rightChild); printf("%d\t", root->keyValue); } }
后序遍历的非递归实现与先序和中序有点不同,每个中间节点都需要被入栈两次,第一次:找到其树的最做节点;第二次:输出左节点之后,需要利用其找到右节点。只有当第二次入栈再取出后才输出具体的值。因为需要用一个标志,标志第几次入栈。具体实现:
//后序--非递归 void PostOrderTra2(PNode root) { int flag[30]; //用一个标记,标记右子树是否访问过 stack<PNode> myStack; if (!root) { printf("树为空!\n"); return; } while (root !=NULL ) { //首先将所有的左子树入栈 myStack.push(root); flag[myStack.size()] = 0; root = root->leftChild; } while (!myStack.empty()) { root = myStack.top(); if (root->rightChild&&flag[myStack.size()] == 0) { //如果是第一次访问,则还不能输出,需要找到其右子树,将右子树入栈 flag[myStack.size()] = 1; root = root->rightChild; while (root) { myStack.push(root); flag[myStack.size()] = 0; root = root->leftChild; } } root = myStack.top(); //第二次出栈,可以输出了 printf("%d\t", root->keyValue); myStack.pop(); } printf("\n"); }
2.4 按层次遍历
按层次遍历即一层层的输出节点值,我这里将根节点视为0层,往下层次依次加1.先定义一个辅助函数,求树的最大深度。
//辅助函数,求树的最大深度 int getDeep(PNode root) { if (!root) { return 0; } int leftDeep = getDeep(root->leftChild) + 1; int rightDeep = getDeep(root->rightChild) + 1; return leftDeep > rightDeep ? leftDeep : rightDeep; }
然后定义一个函数输出指定层的节点
//输出指定的层,将根节点视为0层 int LevelOrderTra(PNode root,int level) { if (!root || level < 0) { printf("%s\t", "NULL"); return 0; } if (level == 0) { printf("%d\t", root->keyValue); return 1; } return LevelOrderTra(root->leftChild, level - 1) + LevelOrderTra(root->rightChild, level - 1); }
最后输出所有的层
//从根节点开始打印出所有层 void printByLevel(PNode root, int deep) { for (int i = 0; i < deep; i++) { LevelOrderTra(root, i); } printf("\n"); }
按层输出的非递归方式,利用队列。先访问树的根节点,输出值。然后将其左右孩子分别加入队列。然后取出队头元素,输出值,在将其左右孩子加入队列。。。。。直到队列为空。具体实现:
//法2,利用队列,实现安层次遍历 void printByLevel2(PNode root) { if (!root) { printf("树为空!\n"); } queue<PNode> myQueue; myQueue.push(root); while (!myQueue.empty()) { root = myQueue.front(); myQueue.pop(); printf("%d\t", root->keyValue); if (root->leftChild)myQueue.push(root->leftChild); if (root->rightChild) myQueue.push(root->rightChild); } }
3 平衡二叉树的查找
相对于插入来说,查找算是非常简单了。平衡二叉树的优点也正是因为其查找效率很高。具体实现。
/*=====================查找===================*/ int SearchTree(PNode root, dataType key) { if (root->keyValue == key) { return 1; } else if (key > root->keyValue && root->rightChild) { return SearchTree(root->rightChild, key); } else if(key < root->keyValue && root->leftChild) { return SearchTree(root->leftChild, key); } else { return 0; } }
4 平衡二叉树的删除
平衡二叉树的删除思路和二叉排序树相同,只是多了个调整的过程,调整思路和插上相似。这里直接给出代码吧。
/*=======================删除==================*/ bool delNode(PNode &root, dataType key,bool &shorter) { if (root == NULL) { return false; } else if (key == root->keyValue) { PNode tmp = NULL; if (root->leftChild == NULL) { tmp = root; root = root->rightChild; delete tmp; shorter = true; } else if (root->rightChild == NULL) { tmp = root; root = root->leftChild; delete tmp; shorter = true; } else { tmp = root->leftChild; while (tmp->rightChild) { tmp = tmp->rightChild; } root->keyValue = tmp->keyValue; delNode(root->leftChild, tmp->keyValue, shorter); } } else if (key < root->keyValue) { if (!delNode(root->leftChild, key, shorter)) { return false; } if (shorter) { switch (root->BalanceFactor) { case LH: root->BalanceFactor = EH; shorter = true; break; case RH: rightBalance(&root); if (root->rightChild->BalanceFactor == EH) { shorter = false; } else { shorter = true; } break; case EH: root->BalanceFactor = RH; shorter = false; break; } } } else { if (!delNode(root->rightChild, key, shorter)) { return false; } if (shorter) { switch (root->BalanceFactor) { case LH: leftBalance(&root); if (root->leftChild->BalanceFactor == EH) { shorter = false; } else { shorter = true; } break; case EH: root->BalanceFactor = LH; shorter = false; break; case RH: root->BalanceFactor = EH; shorter = true; break; } } } return true; }
5 整个项目的代码,包括验证部分
// AVLTree.cpp: 定义控制台应用程序的入口点。 //平衡二叉树 // #include "stdafx.h" #include<stdio.h> #include<stdlib.h> #include<stack> #include<queue> using namespace std; typedef int dataType; #define EH 0 //左右子树一样高 #define LH 1 //左子树比右子树高 #define RH -1 //右子树比左子树高 //定义节点结构 typedef struct Node { dataType keyValue; //数据 int BalanceFactor; //平衡因子 struct Node *leftChild, *rightChild; }*PNode; //为新建一个节点 PNode createNode(dataType keyValue) { PNode newNode = (PNode)malloc(sizeof(Node)); newNode->keyValue = keyValue; newNode->BalanceFactor = EH; newNode->leftChild = NULL; newNode->rightChild = NULL; return newNode; } //右旋 顺时针旋转 void R_Rotate(PNode* node) { PNode tmp = (*node)->leftChild; (*node)->leftChild = tmp->rightChild; tmp->rightChild = (*node); (*node) = tmp; } //左旋,逆时针旋转 void L_Rotate(PNode* node) { PNode tmp = (*node)->rightChild; (*node)->rightChild = tmp->leftChild; tmp->leftChild = (*node); (*node) = tmp; } //左边失衡调整 void leftBalance(PNode* node) { PNode leftchild = (*node)->leftChild; PNode tmpRightChild = NULL; switch (leftchild->BalanceFactor) { case LH: //LL型失衡 (*node)->BalanceFactor = leftchild->BalanceFactor = EH; R_Rotate(node); break; case RH: //LR型失衡 tmpRightChild = leftchild->rightChild; switch (tmpRightChild->BalanceFactor) { case LH: (*node)->BalanceFactor = RH; leftchild->BalanceFactor = EH; break; case EH: (*node)->BalanceFactor = leftchild->BalanceFactor = EH; break; case RH: (*node)->BalanceFactor = EH; leftchild->BalanceFactor = LH; break; } tmpRightChild->BalanceFactor = EH; L_Rotate(&(*node)->leftChild); R_Rotate(node); break; } } //右边失衡调整 void rightBalance(PNode* node) { PNode rightchild = (*node)->rightChild; PNode tmpChild = NULL; switch (rightchild->BalanceFactor) { case RH: //RR型失衡 (*node)->BalanceFactor = rightchild->BalanceFactor = EH; L_Rotate(node); break; case LH: //RL型失衡 tmpChild = rightchild->leftChild; switch (tmpChild->BalanceFactor) { case LH: (*node)->BalanceFactor = EH; rightchild->BalanceFactor = RH; break; case EH: (*node)->BalanceFactor = rightchild->BalanceFactor = EH; break; case RH: (*node)->BalanceFactor = EH; rightchild->BalanceFactor = LH; break; } tmpChild->BalanceFactor = EH; R_Rotate(&(*node)->rightChild); L_Rotate(node); break; } } //插入新值,higher用于判定是否需要调整平衡因子 int InsertKeyValue(PNode* node, dataType keyValue,bool* higher) { if ((*node) == NULL) { //树中不包含此键值,则新建一个节点, (*node) = createNode(keyValue); *higher=true; } else if ((*node)->keyValue == keyValue) { //树中已经包含此键值,则不需要插入 *higher = false; return 0; } else if (keyValue < (*node)->keyValue) { //插入到左子树中 if (!InsertKeyValue(&(*node)->leftChild, keyValue, higher)) //如果左子树中存在该节点 return 0; if (*higher) { switch ((*node)->BalanceFactor) { case LH: leftBalance(node); *higher = false; break; case RH: (*node)->BalanceFactor = EH; *higher = false; break; case EH: (*node)->BalanceFactor = LH; *higher = true; break; } } } else { if (!InsertKeyValue(&(*node)->rightChild, keyValue,higher)) //如果右子树中存在该节点 return 0; if (*higher) { switch ((*node)->BalanceFactor) { case LH: (*node)->BalanceFactor = EH; *higher = false; break; case RH: rightBalance(node); *higher = false; break; case EH: (*node)->BalanceFactor = RH; *higher = true; break; } } } return 1; } //按关系输出,便于检验数的构造是否正确 void printfTree(PNode root) { if (root) { if (root->leftChild) { printf("%d is %d's left child\n", root->leftChild->keyValue, root->keyValue); printfTree(root->leftChild); } if (root->rightChild) { printf("%d is %d's right child\n", root->rightChild->keyValue, root->keyValue); printfTree(root->rightChild); } } } /*=================================遍历:递归和非递归=========================*/ //中序--递归 void InorderTra(PNode root) { if (root) { InorderTra(root->leftChild); printf("%d\t", root->keyValue); InorderTra(root->rightChild); } } //中序--非递归 void InorderTra2(PNode root) { if (!root) { printf("树为空!\n"); } stack<PNode> myStack; while (root|| !myStack.empty()) { //找到最左边的节点,并将路径上的几点压入栈中 while (root) { myStack.push(root); root = root->leftChild; } root = myStack.top(); //取栈顶的值 myStack.pop(); //从栈中删除 printf("%d\t", root->keyValue); root=root->rightChild; } printf("\n"); } //前序遍历 //前序--递归 void PreOrderTra(PNode root) { if (root != NULL) { printf("%d\t", root->keyValue); PreOrderTra(root->leftChild); PreOrderTra(root->rightChild); } } //前序--非递归 void PreOrderTra2(PNode root) { if (!root) { printf("树为空!\n"); } stack<PNode> myStack; while (root || !myStack.empty()) { while (root) { myStack.push(root); printf("%d\t", root->keyValue); root = root->leftChild; } root = myStack.top(); myStack.pop(); root = root->rightChild; } printf("\n"); } //后序遍历 //后序--递归 void PostOrderTra(PNode root) { if (root) { PostOrderTra(root->leftChild); PostOrderTra(root->rightChild); printf("%d\t", root->keyValue); } } //后序--非递归 void PostOrderTra2(PNode root) { int flag[30]; //用一个标记,标记右子树是否访问过 stack<PNode> myStack; if (!root) { printf("树为空!\n"); return; } while (root !=NULL ) { //首先将所有的左子树入栈 myStack.push(root); flag[myStack.size()] = 0; root = root->leftChild; } while (!myStack.empty()) { root = myStack.top(); if (root->rightChild&&flag[myStack.size()] == 0) { //如果是第一次访问,则还不能输出,需要找到其右子树,将右子树入栈 flag[myStack.size()] = 1; root = root->rightChild; while (root) { myStack.push(root); flag[myStack.size()] = 0; root = root->leftChild; } } root = myStack.top(); //第二次出栈,可以输出了 printf("%d\t", root->keyValue); myStack.pop(); } printf("\n"); } //按层次遍历 //辅助函数,求树的最大深度 int getDeep(PNode root) { if (!root) { return 0; } int leftDeep = getDeep(root->leftChild) + 1; int rightDeep = getDeep(root->rightChild) + 1; return leftDeep > rightDeep ? leftDeep : rightDeep; } //输出指定的层,将根节点视为0层 int LevelOrderTra(PNode root,int level) { if (!root || level < 0) { printf("%s\t", "NULL"); return 0; } if (level == 0) { printf("%d\t", root->keyValue); return 1; } return LevelOrderTra(root->leftChild, level - 1) + LevelOrderTra(root->rightChild, level - 1); } //从根节点开始打印出所有层 void printByLevel(PNode root, int deep) { for (int i = 0; i < deep; i++) { LevelOrderTra(root, i); } printf("\n"); } //法2,利用队列,实现安层次遍历 void printByLevel2(PNode root) { if (!root) { printf("树为空!\n"); } queue<PNode> myQueue; myQueue.push(root); while (!myQueue.empty()) { root = myQueue.front(); myQueue.pop(); printf("%d\t", root->keyValue); if (root->leftChild)myQueue.push(root->leftChild); if (root->rightChild) myQueue.push(root->rightChild); } } /*=====================查找===================*/ int SearchTree(PNode root, dataType key) { if (root->keyValue == key) { return 1; } else if (key > root->keyValue && root->rightChild) { return SearchTree(root->rightChild, key); } else if(key < root->keyValue && root->leftChild) { return SearchTree(root->leftChild, key); } else { return 0; } } /*=======================删除==================*/ bool delNode(PNode &root, dataType key,bool &shorter) { if (root == NULL) { return false; } else if (key == root->keyValue) { PNode tmp = NULL; if (root->leftChild == NULL) { tmp = root; root = root->rightChild; delete tmp; shorter = true; } else if (root->rightChild == NULL) { tmp = root; root = root->leftChild; delete tmp; shorter = true; } else { tmp = root->leftChild; while (tmp->rightChild) { tmp = tmp->rightChild; } root->keyValue = tmp->keyValue; delNode(root->leftChild, tmp->keyValue, shorter); } } else if (key < root->keyValue) { if (!delNode(root->leftChild, key, shorter)) { return false; } if (shorter) { switch (root->BalanceFactor) { case LH: root->BalanceFactor = EH; shorter = true; break; case RH: rightBalance(&root); if (root->rightChild->BalanceFactor == EH) { shorter = false; } else { shorter = true; } break; case EH: root->BalanceFactor = RH; shorter = false; break; } } } else { if (!delNode(root->rightChild, key, shorter)) { return false; } if (shorter) { switch (root->BalanceFactor) { case LH: leftBalance(&root); if (root->leftChild->BalanceFactor == EH) { shorter = false; } else { shorter = true; } break; case EH: root->BalanceFactor = LH; shorter = false; break; case RH: root->BalanceFactor = EH; shorter = true; break; } } } return true; } //void delNode2(PNode &root, dataType key) { // if (!root) { // printf("树为空!\n"); // return; // } // else if (!SearchTree(root, key)) { // printf("树中不存在值为%d的节点\n", key); // }else{ // PNode current = root; // while (current->keyValue != key) { // if (key < current->keyValue) current = current->leftChild; // else current = current->rightChild; // } // if (current->leftChild && current->rightChild) { // PNode minNode = current->rightChild; // while (minNode) { // minNode = minNode->leftChild; // } // current->keyValue = minNode->keyValue; // PNode tmp = minNode; // minNode = minNode->rightChild; // delete tmp; // } // else if (current->leftChild || current->rightChild) { // PNode tmp=current; // current = current->leftChild ? current->leftChild : current->rightChild; // delete tmp; // } // else { // PNode tmp=current; // current =NULL; // delete tmp; // } // } //} int main() { int i, dataArr[] = { 1,23,45,34,98,9,4,35,23,36,37,90,85,80 }; PNode treeRoot = NULL; bool heigher; for (i = 0; i < 14; i++) { InsertKeyValue(&treeRoot, dataArr[i],&heigher); /*printfTree(treeRoot); printf("\n\n");*/ } /*printf("中序遍历是:"); InorderTra(treeRoot); printf("\n"); InorderTra2(treeRoot);*/ /*printf("前序遍历是:"); PreOrderTra(treeRoot); printf("\n"); PreOrderTra2(treeRoot);*/ /*printf("后序遍历是:"); PostOrderTra(treeRoot); printf("\n"); PostOrderTra2(treeRoot);*/ /*printf("deep:%d\n", getDeep(treeRoot));*/ printf("层次遍历是:"); printByLevel(treeRoot, getDeep(treeRoot)); printf("\n"); /*printByLevel2(treeRoot);*/ //测试查找 /*while (true) { printf("请输入要查找的值:"); int key; scanf("%d", &key); printf("\n查找结果:%d\n", SearchTree(treeRoot, key)); }*/ //测试删除 while (true) { printf("请输入要删除的值:"); int key; scanf("%d", &key); bool shoter = false; delNode(treeRoot, key,shoter); /*delNode2(treeRoot, key);*/ printByLevel(treeRoot,4); } return 0; }