AVL树插入例程非递归实现C语言

  终于完成了AVL树插入例程的非递归实现.

话说我是前天开始接触AVL树,今天用了一天时间完成了非递归插入例程.准确地说,应该是6小时.即使测试正确,还是愿意以此种形式温习、理解一下.也想显摆显摆,因为在我看来,学AVL树第三天写出非递归插入例程很了不起了.如果你觉得我好笑,那你也不应该怪我,你该认为我是一个笨到用了三天才解决此问题又在这里炫耀的一个可悲的人;如果你觉得我了不起,那么我是一个天才.

  后记:今天又弄了大约3个小时才彻底弄完…哎,昨天的话说得好冒失,,,不过留在那里就当警钟了.. 呵呵

  主要思路就是:AddItem ()为执行该任务函数.该函数接受一个Tree类型的变量和一个Item类型的变量作为参数,返回一个Tree类型的变量.

  该函数需要创建一个栈来保存在新添加结点路径上出现过的结点变量,也就是Position类型的数据.之前保存了Position *类型的数据,也就是保存了&scan,结果后来发现这样栈中的内容会随着scan的改变而改变.选择栈主要是看中了栈先进后出的特性,以及它大小的伸缩性.起初想到了使用数组,可是数组必须事先指定大小,我希望我的每一个函数都是希望根据他的实际参数来调整自身,而不是使用一些常量,即使是常量,那些没有任何科学根据的常量我也不想使用.

  通过先找到被添加结点位置的父结点,之后向该结点的left或right指针添加该结点.出现过的结点入栈.

  添加完毕后,通过栈不为空的条件进行循环,并对栈顶当前内容进行检查.检查的是当前结点左子树与右子树高度差.该高度差我使用的是Height_Calculatr ()函数来实现,该函数通过递归的方式获得当前结点的高度.我有意地使用了递归,当做练习.循环的话,我简单思考了一下,感觉略难,于是索性练习之前并不熟悉的递归.后来察觉到这个函数在处理高度时对于当前结点为NULL或者当前结点是叶节点的情况下都返回0.应对于这个缺陷,我在AddItem ()中添加了对当前结点左右子结点的检测,如果为NULL就将高度值赋为-1.这样就能够处理此种情况.

  递归结束后,返回Tree类型的新AVL树,就实现了.

  Tree AddItem (Tree tree, const Item item) { Position scan = tree ; Stack stack ; Stack_Item temp ; int lenth_left, lenth_right ; Initialize_Stack (&stack) ; if (AVLTreeIsEmpty (tree)) { tree = Make_Node (item) ; return tree ; } while (scan != NULL) { /* 把当前结点地址压进栈里 */ Push (&stack, scan) ; if (Left_Above_And_Beyond_Right (item, scan -> item)) { /* 此时的 scan 是新结点的父节点 */ if (NULL == scan -> right) break ; else scan = scan -> right ; } else if (Left_Is_Less_Than_Right (item, scan -> item)) { /* 此时的 scan 是新结点的父节点 */ if (NULL == scan -> left) break ; else scan = scan -> left ; } /* 否则,出现了将要重复添加的情况 */ else return tree ; } /* 接下来添加结点 */ if (Left_Above_And_Beyond_Right (item, scan -> item)) scan -> right = Make_Node (item) ; else if (Left_Is_Less_Than_Right (item, scan -> item)) scan -> left = Make_Node (item) ; /* 创建新结点失败的情况下 */ if (NULL == scan) return tree ; while (!Stack_Is_Empty (&stack)) { temp = Top (&stack) ; if (NULL == temp -> left) lenth_left = -1 ; else lenth_left = Height_Calculate (temp -> left) ; if (NULL == temp -> right) lenth_right = -1 ; else lenth_right = Height_Calculate (temp -> right) ; if (2 == lenth_left – lenth_right) { if (Left_Above_And_Beyond_Right (item, temp -> left -> item)) { if (tree == temp) tree = New_Double_Rotate_With_Left (temp) ; else temp = New_Double_Rotate_With_Left (temp) ; } else { if (tree == temp) tree = Single_Rotate_With_Left (temp) ; else temp = Single_Rotate_With_Left (temp) ; } } if (2 == lenth_right – lenth_left) { if (Left_Above_And_Beyond_Right (item, temp -> right -> item)) { if (tree == temp) tree = Single_Rotate_With_Right (temp) ; else temp = Single_Rotate_With_Right (temp) ; } else { if (tree == temp) tree = New_Double_Rotate_With_Right (temp) ; else temp = New_Double_Rotate_With_Right (temp) ; } } Pop (&stack) ; } Empty_The_Stack (&stack) ; return tree ; }

  接下来贴出计算当前节点高度的函数

static int Height_Calculate (Position position) { int count_left, count_right ; count_left = count_right = 0 ; if (position != NULL) { count_left = Height_Calculate (position -> left) ; count_right = Height_Calculate (position -> right) ; if (position -> left != NULL) count_left++ ; if (position -> right != NULL) count_right++ ; } return count_left >= count_right ? count_left : count_right ; }

  接下来是单旋转,双旋转函数

static Position Single_Rotate_With_Left (Position K2) { Position K1 ; K1 = K2 -> left ; K2 -> left = K1 -> right ; K1 -> right = K2 ; K2 -> height = Max (Height_Count (K2 -> left), Height_Count (K2 -> right)) + 1 ; K1 -> height = Max (Height_Count (K1 -> left), K2 -> height) + 1 ; return K1 ; } static Position Single_Rotate_With_Right (Position K2) { Position K1 ; K1 = K2 -> right ; K2 -> right = K1 -> left ; K1 -> left = K2 ; K2 -> height = Max (Height_Count (K2 -> left), Height_Count (K2 -> right)) + 1 ; K1 -> height = Max (Height_Count (K1 -> right), K2 -> height) + 1 ; return K1 ; } static Position Double_Rotate_With_Left (Position K3) { K3 -> left = Single_Rotate_With_Right (K3 -> left) ; return Single_Rotate_With_Left (K3) ; } static Position Double_Rotate_With_Right (Position K3) { K3 -> right = Single_Rotate_With_Left (K3 -> right) ; return Single_Rotate_With_Right (K3) ; }

  在这之后,我又写了两个新的双旋转函数,从原理上解决了双旋转.我所说的原理上,是在我纸上画的图上,呵呵

static Position New_Double_Rotate_With_Left (Position K3) { Position K2, K1 ; K2 = K3 -> left ; K1 = K2 -> right ; K2 -> right = K1 -> left ; K1 -> left = K2 ; K3 -> left = K1 -> right ; K1 -> right = K3 ; return K1 ; } static Position New_Double_Rotate_With_Right (Position K3) { Position K2, K1 ; K2 = K3 -> right ; K1 = K2 -> left ; K2 -> left = K1 -> right ; K1 -> right = K2 ; K3 -> right = K1 -> left ; K1 -> left = K3 ; return K1 ; }

终于,还是完成了.感觉到自己缺乏计算机基础知识,工作原理机制的知识.也就是说,在寄存器,内存之间的基本指令上.对于函数的返回值使用以及向其它函数传递变量地址来改变变量,这些的这些,还比较糊涂.

    原文作者:AVL树
    原文地址: https://blog.csdn.net/Golden_Shadow/article/details/5918325
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞