之前寫過一個二叉尋找樹,其中最麻煩的是刪除元素的方法,一共分了8種情況,主要是要區分是否是根節點和非根節點,
寫的太煩了,詳細請參見:http://blog.csdn.net/todd911/article/details/8471566
今天要來簡化一下這個方法,之前我還寫過一篇《簡潔的單項鏈表插入操作》,利用雙指標,簡化了根節點和非根節點的區別,
詳細請參見:http://blog.csdn.net/todd911/article/details/8941593,其實在二叉尋找樹中也可以使用這種方法。
改進後的代碼如下:
void deleteNode(treeNode** node, int value){ treeNode* current; while( (current = *node) != NULL && current->value != value ){ if(current->value > value){ node = ¤t->left; }else if(current->value < value){ node = ¤t->right; } }//如果current為NULL,則沒有找到 if(current == NULL){ printf("this node want to delete is not exit!\n"); }else{//如果找到節點,則判斷節點的狀態//沒有孩子節點,則直接刪除 if(current->left == NULL && current->right == NULL){ free(current); *node = NULL; current = NULL; }else //左右孩子都有,則先將右孩子插入到左孩子樹上,再將原先指向current的指標指向current的左孩子,刪除currentif(current->left != NULL && current->right != NULL){ insertNode(current->left, current->right); *node = current->left; free(current); current = NULL; }else //沒有左孩子,有右孩子,則將原先指向current的指標指向current的右孩子,刪除currentif(current->left == NULL && current->right != NULL){ *node = current->right; free(current); current = NULL; }else //沒有右孩子,有左孩子,則將原先指向current的指標指向current的左孩子,刪除currentif(current->left != NULL && current->right == NULL){ *node = current->left; free(current); current = NULL; } }}
這種方法有一個問題,就是被刪除的節點都有左右孩子,就會先將右孩子插入到左孩子樹上,再將原先指向current的指標指向current的左孩子,
導致二叉樹的樹榦長度不平衡了。
詳細步驟如下,節點12是要被刪除的:
可見,最後樹的結構破壞比較大, 可能會導致尋找的效率降低。
下面我們來改進一下,如果要被刪除的節點有左右孩子,則從左孩子獲得值最大的那個,來替換要被刪除的節點,詳細步驟如下,節點12是要被刪除的:
怎麼樣,樹的結構沒有怎麼被破壞吧,推薦還是使用這種方法比較好。
下面附上完整的sample代碼:
#include <stdio.h>#include <stdlib.h>#define SIZE 10typedef struct tagNode{ int value; struct tagNode* left; struct tagNode* right;}treeNode;void displayArray(int array[],int size){ printf("the array is:"); int i; for(i=0;i<size;i++){ printf("%d ",array[i]); } printf("\n");}void displayTree(treeNode* node){ if(node == NULL) return; if(node->left != NULL){ displayTree(node->left); } printf("%d ",node->value); if(node->right != NULL){ displayTree(node->right); }}void insertNode(treeNode* node, treeNode* iNode){ if(iNode->value >= node->value && node->right != NULL){ insertNode(node->right, iNode); return; } if(iNode->value < node->value && node->left != NULL){ insertNode(node->left, iNode); return; } if(iNode->value >= node->value && node->right == NULL){ node->right = iNode; } if(iNode->value < node->value && node->left == NULL){ node->left = iNode; }}void deleteNode(treeNode** node, int value){ treeNode* current; while( (current = *node) != NULL && current->value != value ){ if(current->value > value){ node = ¤t->left; }else if(current->value < value){ node = ¤t->right; } } if(current == NULL){ printf("this node want to delete is not exit!\n"); }else{ if(current->left == NULL && current->right == NULL){ free(current); *node = NULL; current = NULL; }else if(current->left != NULL && current->right != NULL){ insertNode(current->left, current->right); *node = current->left; free(current); current = NULL; }else if(current->left == NULL && current->right != NULL){ *node = current->right; free(current); current = NULL; }else if(current->left != NULL && current->right == NULL){ *node = current->left; free(current); current = NULL; } }}void getMaxValueNode(treeNode **link){ while( *link != NULL && (*link)->right != NULL){ *link = (*link)->right; };}void deleteNode2(treeNode** node, int value){ treeNode* current; while( (current = *node) != NULL && current->value != value ){ if(current->value > value){ node = ¤t->left; }else if(current->value < value){ node = ¤t->right; } } if(current == NULL){ printf("this node want to delete is not exit!\n"); }else{ if(current->left == NULL && current->right == NULL){ free(current); *node = NULL; current = NULL; }else if(current->left != NULL && current->right != NULL){ treeNode** link = ¤t->left; getMaxValueNode(link); if(*link != NULL){ treeNode *maxValueNode = *link; *link = (*link)->left; maxValueNode->left = current->left; maxValueNode->right = current->right; *node = maxValueNode; free(current); current = NULL; } }else if(current->left == NULL && current->right != NULL){ *node = current->right; free(current); current = NULL; }else if(current->left != NULL && current->right == NULL){ *node = current->left; free(current); current = NULL; } }}void createTree(treeNode** root, int array[], int size){ int i; *root = (treeNode*)malloc(sizeof(treeNode)); (*root)->value = array[0]; (*root)->left = NULL; (*root)->right = NULL; for(i=1;i<size;i++){ treeNode* child = (treeNode*)malloc(sizeof(treeNode)); child->value = array[i]; child->left = NULL; child->right = NULL; insertNode(*root, child); }}void deleteTree(treeNode* node){ if(node == NULL) return; if(node->left != NULL){ deleteTree(node->left); } if(node->right != NULL){ deleteTree(node->right); } if(node->left == NULL && node->right == NULL){ free(node); node = NULL; }}int main(int argc, char* argv[]){ int array[SIZE] = {60,4,45,78,345,23,12,3,6,21}; displayArray(array,SIZE); treeNode *root = NULL; createTree(&root, array, SIZE); printf("the tree is(left->middle->right):"); displayTree(root); printf("\n"); int value = 12; printf("delete value:%d\n",value); deleteNode(&root,value); printf("the tree is(left->middle->right):"); displayTree(root); printf("\n"); value = 78; printf("delete value:%d\n",value); deleteNode2(&root,value); printf("the tree is(left->middle->right):"); displayTree(root); printf("\n"); deleteTree(root); return 0;}