// sl-4-DHBW-Inf2 // avl binary search tree: insert, find, delete, fibo tree #include #include #include "suchbaum.h" #include "avlbaum.h" #include "visualbinbaum.h" using namespace std; /////////////////////////////////////////////////////////////////////////////// void avl3PtrSwap(avlPtr &p1, avlPtr &p2, avlPtr &p3) { /////////////////////////////////////////////////////////////////////////////// avlPtr ph=p1; p1=p2; p2=p3; p3=ph; } /////////////////////////////////////////////////////////////////////////////// void avlRotate(avlPtr &root) { /////////////////////////////////////////////////////////////////////////////// // balance changed by another one, so ... if (root->balance==unbalancedright) { // height difference is two now if (root->right->balance==unbalancedright) { cout << "Left rotation @ " << root->value << "--" << root->right->value << endl; avl3PtrSwap(root,root->right,root->right->left); root->balance=balanced; root->left->balance=balanced; cout << "Nodes " << root->left->value << " and " << root->value << " are now balanced" << endl; } else if (root->right->balance==unbalancedleft) { cout << "Right+left rotation" << endl; cout << "Right rotation @ " << root->right->left->value << "--" << root->right->value << endl; avl3PtrSwap(root->right,root->right->left,root->right->left->right); cout << "Subtree after right rotation (balances will be corrected after the 2nd rotation):" << root; cout << "Left rotation @ " << root->value << "--" << root->right->value << endl; avl3PtrSwap(root,root->right,root->right->left); // new balanced depend on the former balance of the new root if (root->balance==unbalancedleft) { root->balance=balanced; root->left->balance=balanced; root->right->balance=unbalancedright; cout << "Nodes " << root->left->value << " and " << root->value << " are now balanced, node" << root->right->value << " is unbalanced to the right" << endl; } else if (root->balance==balanced) { root->balance=balanced; root->left->balance=balanced; root->right->balance=balanced; cout << "Nodes " << root->left->value << ", " << root->value << ", and " << root->right->value << " are now balanced" << endl; } else { // root->balance==unbalancedright root->balance=balanced; root->left->balance=unbalancedleft; root->right->balance=balanced; cout << "Node " << root->left->value << " is now unbalanced to the right, " << root->value << " and " << root->right->value << " are now balanced" << endl; } } else { // root->right->balance==balanced - can only happen during delete cout << "Left rotation @ " << root->value << "--" << root->right->value << endl; avl3PtrSwap(root,root->right,root->right->left); root->balance=unbalancedleft; root->left->balance=unbalancedright; cout << "Node " << root->left->value << " is now unbalanced to the right, and " << root->value << " is now unbalanced to the left" << endl; } // cases left and right+left rotation done } else { // root->balance==unbalancedleft // height difference is now -2 if (root->left->balance==unbalancedleft) { cout << "Right rotation @ " << root->left->value << "--" << root->value << endl; avl3PtrSwap(root,root->left,root->left->right); root->balance=balanced; root->right->balance=balanced; cout << "Nodes " << root->value << " and " << root->right->value << " are now balanced" << endl; } else if (root->left->balance==unbalancedright) { cout << "Left+right rotation" << endl; cout << "Left rotation @ " << root->left->value << "--" << root->left->right->value << endl; avl3PtrSwap(root->left,root->left->right,root->left->right->left); cout << "Subtree after left rotation (balances will be corrected after the 2nd rotation):" << root; cout << "Right rotation @ " << root->left->value << "--" << root->value << endl; avl3PtrSwap(root,root->left,root->left->right); // new balanced depend on the former balance of the new root if (root->balance==unbalancedleft) { root->balance=balanced; root->left->balance=balanced; root->right->balance=unbalancedright; cout << "Nodes " << root->left->value << " and " << root->value << " are now balanced, node" << root->right->value << " is unbalanced to the right" << endl; } else if (root->balance==balanced) { root->balance=balanced; root->left->balance=balanced; root->right->balance=balanced; cout << "Nodes " << root->left->value << ", " << root->value << ", and " << root->right->value << " are now balanced" << endl; } else { // root->balance==unbalancedright root->balance=balanced; root->left->balance=unbalancedleft; root->right->balance=balanced; cout << "Node " << root->left->value << " is now unbalanced to the left, " << root->value << " and " << root->right->value << " are now balanced" << endl; } } else { // root->right->balance==balanced - can only happen during delete cout << "Right rotation @ " << root->left->value << "--" << root->value << endl; avl3PtrSwap(root,root->left,root->left->right); root->balance=unbalancedright; root->right->balance=unbalancedleft; cout << "Node " << root->value << " is now unbalanced to the right, and " << root->right->value << " is now unbalanced to the left" << endl; } // cases right and left+right rotation done } } /////////////////////////////////////////////////////////////////////////////// void avlInsertH(avlPtr & root, const DataType value, bool & higher) { /////////////////////////////////////////////////////////////////////////////// if (root==NULL) { root = new avlTree; root->value = value; root->left = root->right = 0; root->balance = balanced; higher=true; } else if (valuevalue) { avlInsertH(root->left,value,higher); if (higher) { if (root->balance==unbalancedleft) { cout << "Rotation necessary @ " << root->value << " -- subtree:" << root; avlRotate(root); higher=false; cout << "Tree is now avl again" << endl; } else if (root->balance==balanced) { root->balance=unbalancedleft; // higher is still true cout << "Node " << root->value << " is now unbalanced to the left" << endl; } else { // root->balance==unbalancedright root->balance=balanced; higher=false; cout << "Node " << root->value << " is now balanced" << endl; } } } else if (value>root->value) { avlInsertH(root->right,value,higher); if (higher) { if (root->balance==unbalancedleft) { root->balance=balanced; higher=false; cout << "Node " << root->value << " is now balanced" << endl; } else if (root->balance==balanced) { root->balance=unbalancedright; // higher is still true cout << "Node " << root->value << " is now unbalanced to the right" << endl; } else { // root->balance==unbalancedright cout << "Rotation necessary @ " << root->value << " -- subtree:" << root; avlRotate(root); higher=false; cout << "Tree is now avl again" << endl; } } } else { // it is == cout << "Element " << value << " is already in the tree!" << endl; } } /////////////////////////////////////////////////////////////////////////////// void avlInsert(avlPtr & root, const DataType value) { /////////////////////////////////////////////////////////////////////////////// bool higher = false; avlInsertH(root,value,higher); } /////////////////////////////////////////////////////////////////////////////// bool avlFind(const avlPtr root, const DataType value) { /////////////////////////////////////////////////////////////////////////////// if (root==NULL) { return false; } else if (valuevalue) { return avlFind(root->left,value); } else if (value>root->value) { return avlFind(root->right,value); } else { // it is == return true; } } /////////////////////////////////////////////////////////////////////////////// void avlDeleteH(avlPtr & root, const DataType value, bool & lower, bool & deleted) { /////////////////////////////////////////////////////////////////////////////// if (root==NULL) { cout << "Element " << value << " isn't in the tree!" << endl; lower=false; deleted=false; // no, the element was not in the tree } else if (valuevalue) { avlDeleteH(root->left,value,lower,deleted); if (lower) { if (root->balance==unbalancedleft) { root->balance=balanced; cout << "Node " << root->value << " is now balanced" << endl; // lower is still true } else if (root->balance==balanced) { root->balance=unbalancedright; lower=false; cout << "Node " << root->value << " is now unbalanced to the right" << endl; } else { // root->balance==unbalancedright if (root->right->balance==balanced) { lower=false; } // else { // lower is still true after rotation cout << "Rotation necessary @ " << root->value << " -- subtree:" << root; avlRotate(root); } } } else if (value>root->value) { avlDeleteH(root->right,value,lower,deleted); if (lower) { if (root->balance==unbalancedleft) { if (root->left->balance==balanced) { lower=false; } // else { // lower is still true after rotation cout << "Rotation necessary @ " << root->value << " -- subtree:" << root; avlRotate(root); } else if (root->balance==balanced) { root->balance=unbalancedleft; lower=false; cout << "Node " << root->value << " is now unbalanced to the left" << endl; } else { // root->balance==unbalancedright root->balance=balanced; cout << "Node " << root->value << " is now balanced" << endl; // lower is still true } } } else { // it is == cout << "Element " << value << " is in the tree, I'll delete it!" << endl; if (root->left==NULL && root->right==NULL) { // it's a leaf => delete it delete root; root=NULL; lower=true; // balances will change on path to root } else if (root->left==NULL) { // right subtree must be non-empty, delete root and shift subtree up avlPtr tbd=root; root=root->right; // subtree has just one node, and it's balanced delete tbd; lower=true; // balances will change on path to root } else if (root->right==NULL) { // left subtree must be non-empty, delete root and shift subtree up avlPtr tbd=root; root=root->left; // subtree has just one node, and it's balanced delete tbd; lower=true; // balances will change on path to root } else { // both subtrees are non-empty => find inorder successor s, // copy it's value to root, and delete the value in the right subtree // note: recursion impossible, inorder successor has 1 child or none avlPtr iosucc=root->right; // is not NULL while (iosucc->left!=NULL) { iosucc=iosucc->left; } root->value=iosucc->value; cout << "Copy value of inorder successor " << iosucc->value << " into the node " << value << ", and delete the original " << iosucc->value << " in the right subtree" << endl; avlDeleteH(root->right,iosucc->value,lower,deleted); // this way, subtree was traversed twice (and maybe copying the value // is expensive in case it's a huge struct), but traversing twice // isn't much difference compared to having root's value at hand during // recursion (and we'd have to implement another delete routine, // because we don't know inorder successor's value in advance) // only drawback: if there are other pointers to avl tree's nodes // those pointers will point to the wrong node (due to copying the value) if (lower) { // copied from above avlDeleteH(root->right,... if (root->balance==unbalancedleft) { if (root->left->balance==balanced) { lower=false; } // else { // lower is still true after rotation cout << "Rotation necessary @ " << root->value << " -- subtree:" << root; avlRotate(root); } else if (root->balance==balanced) { root->balance=unbalancedleft; lower=false; cout << "Node " << root->value << " is now unbalanced to the left" << endl; } else { // root->balance==unbalancedright root->balance=balanced; cout << "Node " << root->value << " is now balanced" << endl; // lower is still true } } } deleted=true; // yes, we deleted an element } } /////////////////////////////////////////////////////////////////////////////// bool avlDelete(avlPtr & root, const DataType value) { /////////////////////////////////////////////////////////////////////////////// bool lower = false; bool deleted = false; avlDeleteH(root,value,lower,deleted); return deleted; } /////////////////////////////////////////////////////////////////////////////// void delTree(const avlPtr root) { /////////////////////////////////////////////////////////////////////////////// if (root!=NULL) { delTree(root->left); delTree(root->right); delete root; } } /////////////////////////////////////////////////////////////////////////////// bstPtr avl2bst(const avlPtr root) { /////////////////////////////////////////////////////////////////////////////// if (root==NULL) { return NULL; } else { bstPtr cp = new bsTree(root->value,avl2bst(root->left),avl2bst(root->right)); // cp->value=root->value; // cp->left=avl2bst(root->left); // cp->right=avl2bst(root->right); return cp; } } /////////////////////////////////////////////////////////////////////////////// bstPtr avlbal2bst(const avlPtr root) { /////////////////////////////////////////////////////////////////////////////// if (root==NULL) { return NULL; } else { bstPtr cp = new bsTree(root->balance-1,avlbal2bst(root->left),avlbal2bst(root->right)); // cp->value=root->balance-1; // cp->left=avlbal2bst(root->left); // cp->right=avlbal2bst(root->right); return cp; } } /////////////////////////////////////////////////////////////////////////////// void avlInsertFiboOfHeight(avlPtr & root, const int height) { // // inserts elements of a fibonacci tree of , will be emptied // /////////////////////////////////////////////////////////////////////////////// delTree(root); if (height>1) { int *fibo=new int[height+1]; fibo[0]=1; fibo[1]=1; // = root's value on level [.] // fibo[0]=1 only needed 10 lines below ... for(int i=2; i<=height; i++) { fibo[i]=fibo[i-1]+fibo[i-2]; } // recursive insertion isn't possible (due to induced rotations), use queue const int nrOfNodesInFiboTree = fibo[height]+fibo[height-1]-1; int *fiborder=new int[nrOfNodesInFiboTree]; // order of nodes to be inserted int *fibheight=new int[nrOfNodesInFiboTree]; // heights of fibo trees in above order int front,next; // "queue" index - this pseudo queue is good enough // in a fibo tree root and it's left descendants are fibo nums (1,2,3,5,..) // left subtree's root has value -fibnr[height-2], right +fibnr[height-2] // we can calculate the heights, values and insert them in parallel fibheight[0]=height; fiborder[0]=fibo[height]; avlInsert(root,fiborder[0]); front=0; next=1; while (next1) { // left subtree exists fibheight[next]=fibheight[front]-1; fiborder[next]=fiborder[front]-fibo[fibheight[front]-2]; // fibo[0] needed avlInsert(root,fiborder[next]); next++; } if (fibheight[front]>2) { // right subtree exists fibheight[next]=fibheight[front]-2; fiborder[next]=fiborder[front]+fibo[fibheight[next]]; // +f[h[front]-2] avlInsert(root,fiborder[next]); next++; } front++; } delete fibo; delete fiborder; delete fibheight; } else if (height==1) { root=new avlTree; root->value=1; root->left=root->right=NULL; root->balance=balanced; } // else height<1, root=NULL }