資料結構——二叉排序樹
阿新 • • 發佈:2018-12-02
建立、查詢、刪除
codeblocks 17 通過
#include <iostream> #define KeyType int #define InfoType char using namespace std; typedef struct { KeyType key; // 關鍵字項 InfoType otherinfo; // 其他資料項 }ElemType; // 每個節點的資料型別 typedef struct BSTNode { ElemType data; // 節點的資料項 struct BSTNode *lchild, *rchild; }BSTNode,*BSTree; void InsertBST(BSTree &T, ElemType e) { if(!T) // T根節點為空 { BSTree S = new BSTNode; S->data = e; S->lchild = S->rchild = NULL; T=S; } else if(e.key < T->data.key) InsertBST(T->lchild,e); else if(e.key > T->data.key) InsertBST(T->rchild,e); } void CreateBSTree(BSTree &T) { T = NULL; // 初始化為空樹 int n=15; //cin>>n: while(n>0) { ElemType value; cin>>value.key; InsertBST(T,value); n--; } //cout<<"Create Done !"<<endl; } BSTree SearchBST(BSTree &T, KeyType key) { if((!T)||key==T->data.key) return T; // 查詢結束 返回目標節點或者空指標 else if(key<T->data.key) return SearchBST(T->lchild,key); // 在左子樹中繼續查詢 else return SearchBST(T->rchild,key); // 在右子樹中繼續查詢 } void InOrderTraverse(BSTree T) {// 中序遞迴遍歷 if(T) { InOrderTraverse(T->lchild); cout<<T->data.key<<" "; InOrderTraverse(T->rchild); } } void DeleteBST(BSTree &T, KeyType key) {// 從二叉排序樹T中刪除關鍵字等於key的節點 BSTree p = T, f=NULL, q; // 初始化 /*------下面的while迴圈從根開始查詢關鍵字等於key的節點--------*/ while(p) { if(p->data.key == key) break; f = p; if(p->data.key > key) p = p->lchild; else p = p->rchild; } /*--------分別考慮三種情況,p所指的子樹內部:左右子樹都不為空,無左子樹,無右子樹---------*/ q = p; if((p->lchild)&&(p->rchild)) // 左右子樹都不為空 { BSTree s = p->lchild; while(s->rchild) // 查詢p的左子樹的最右節點,即p的直接前驅 { q=s;s=s->rchild; } p->data=s->data; // 將s的data 賦值給要刪除的節點p,p不能直接delete,需要保持p的左右子樹關係 if(q!=p) // 如果pq不相同,說明s有右子樹 q->rchild=s->lchild; else // qp相同,說明s沒有右子樹 q->lchild=s->lchild; delete s; return; // 刪除結束!!! } else if(!p->rchild) // 無右子樹,只需要重接左子樹 { p = p->lchild; } else if(!p->lchild) // 無左子樹,只需要重接右子樹 { p = p->rchild; } /*-------將p所指的子樹掛接到其雙親節點*f相應位置-----------*/ if(!f) T=p; // 如果刪除的是根節點 else if(q==f->lchild) // q是f的左子樹,p接到f的左子樹位置 f->lchild=p; else // q是f的右子樹,p接到f的右子樹位置 f->rchild=p; delete q; } int main() { BSTree T; CreateBSTree(T); InOrderTraverse(T); cout<<"\n"; BSTree p; KeyType key; cin>>key; p = SearchBST(T,key); if(p) cout<<"查詢成功!"<<endl; else cout<<"not find it!"<<endl; cin>>key; DeleteBST(T,key); InOrderTraverse(T); } /* test data: 輸入: 1 5 4 2 3 6 8 7 9 11 14 13 12 16 19 輸出: 1 2 3 4 5 6 7 8 9 11 12 13 14 16 19 輸入: 19 輸出: 查詢成功! 輸入: 14 輸出: 1 2 3 4 5 6 7 8 9 11 12 13 19 16 */
附圖便於思考刪除演算法
小甲魚老師的程式碼,我加了註釋:
int Delete(BSTree &p) { BSTree q, s; /*-----待刪除的節點只有左或右子樹----*/ if(p->rchild == NULL) { q = p; p = p->lchild; delete q; } else if(p->lchild == NULL) { q = p; p = p->rchild; delete q; } /*-----待刪除的節點有左和右子樹-------*/ else { q = p; s = p->lchild; while(s->rchild) {// 查詢p的直接前驅,s記錄,q是s的雙親 q = s; s = s->rchild; } p->data.key = s->data.key; // 資料替換 if(q != p) // qp不想同,說明p的左子樹有右子樹 q->rchild = s->lchild; else // qp相同,說明p的左子樹沒有右子樹 q->lchild = s->lchild; delete s; } return 1; } int DeleteBST_JiaYu(BSTree &T, KeyType key) {// 返回刪除結果,該函式也可通過呼叫search函式進行查詢,再刪除。 if(!T) return -1; else { if(key == T->data.key) return Delete(T); else if(key>T->data.key) return DeleteBST_JiaYu(T->rchild,key); else return DeleteBST_JiaYu(T->lchild,key); } }
另附圖:
完整程式碼code
// 二叉排序樹 @ChenYe 2018/12/02 #include <iostream> #define KeyType int #define InfoType char using namespace std; typedef struct { KeyType key; // 關鍵字項 InfoType otherinfo; // 其他資料項 }ElemType; // 每個節點的資料型別 typedef struct BSTNode { ElemType data; // 節點的資料項 struct BSTNode *lchild, *rchild; }BSTNode,*BSTree; void InsertBST(BSTree &T, ElemType e) { if(!T) // T根節點為空 { BSTree S = new BSTNode; S->data = e; S->lchild = S->rchild = NULL; T=S; } else if(e.key < T->data.key) InsertBST(T->lchild,e); else if(e.key > T->data.key) InsertBST(T->rchild,e); } void CreateBSTree(BSTree &T) { T = NULL; // 初始化為空樹 int n=15; //cin>>n: while(n>0) { ElemType value; cin>>value.key; InsertBST(T,value); n--; } //cout<<"Create Done !"<<endl; } BSTree SearchBST(BSTree &T, KeyType key) { if((!T)||key==T->data.key) return T; // 查詢結束 返回目標節點或者空指標 else if(key<T->data.key) return SearchBST(T->lchild,key); // 在左子樹中繼續查詢 else return SearchBST(T->rchild,key); // 在右子樹中繼續查詢 } void InOrderTraverse(BSTree T) {// 中序遞迴遍歷 if(T) { InOrderTraverse(T->lchild); cout<<T->data.key<<" "; InOrderTraverse(T->rchild); } } void DeleteBST(BSTree &T, KeyType key) {// 從二叉排序樹T中刪除關鍵字等於key的節點 BSTree p = T, f=NULL, q; // 初始化 /*------下面的while迴圈從根開始查詢關鍵字等於key的節點--------*/ while(p) { if(p->data.key == key) break; f = p; if(p->data.key > key) p = p->lchild; else p = p->rchild; } /*--------分別考慮三種情況,p所指的子樹內部:左右子樹都不為空,無左子樹,無右子樹---------*/ q = p; if((p->lchild)&&(p->rchild)) // 左右子樹都不為空 { BSTree s = p->lchild; while(s->rchild) // 查詢p的左子樹的最右節點,即p的直接前驅 { q=s;s=s->rchild; } p->data=s->data; // 將s的data 賦值給要刪除的節點p,p不能直接delete,需要保持p的左右子樹關係 if(q!=p) // 如果pq不相同,說明s有右子樹 q->rchild=s->lchild; else // qp相同,說明s沒有右子樹 q->lchild=s->lchild; delete s; return; // 刪除結束!!! } else if(!p->rchild) // 無右子樹,只需要重接左子樹 { p = p->lchild; } else if(!p->lchild) // 無左子樹,只需要重接右子樹 { p = p->rchild; } /*-------將p所指的子樹掛接到其雙親節點*f相應位置-----------*/ if(!f) T=p; // 如果刪除的是根節點 else if(q==f->lchild) // q是f的左子樹,p接到f的左子樹位置 f->lchild=p; else // q是f的右子樹,p接到f的右子樹位置 f->rchild=p; delete q; } int Delete(BSTree &p) { BSTree q, s; /*-----待刪除的節點只有左或右子樹----*/ if(p->rchild == NULL) { q = p; p = p->lchild; delete q; } else if(p->lchild == NULL) { q = p; p = p->rchild; delete q; } /*-----待刪除的節點有左和右子樹-------*/ else { q = p; s = p->lchild; while(s->rchild) {// 查詢p的直接前驅,s記錄,q是s的雙親 q = s; s = s->rchild; } p->data.key = s->data.key; // 資料替換 if(q != p) // qp不想同,說明p的左子樹有右子樹 q->rchild = s->lchild; else // qp相同,說明p的左子樹沒有右子樹 q->lchild = s->lchild; delete s; } return 1; } int DeleteBST_JiaYu(BSTree &T, KeyType key) {// 返回刪除結果,該函式也可通過呼叫search函式進行查詢,再刪除。 if(!T) return -1; else { if(key == T->data.key) return Delete(T); else if(key>T->data.key) return DeleteBST_JiaYu(T->rchild,key); else return DeleteBST_JiaYu(T->lchild,key); } } int main() { BSTree T; CreateBSTree(T); InOrderTraverse(T); cout<<"\n"; BSTree p; KeyType key; cin>>key; p = SearchBST(T,key); if(p) cout<<"查詢成功!"<<endl; else cout<<"not find it!"<<endl; cin>>key; DeleteBST(T,key); InOrderTraverse(T); cout<<"\n新增測試,請輸入要刪除的資料:\n"; cin>>key; DeleteBST_JiaYu(T,key); InOrderTraverse(T); } /* test data: 輸入: 1 5 4 2 3 6 8 7 9 11 14 13 12 16 19 輸出: 1 2 3 4 5 6 7 8 9 11 12 13 14 16 19 輸入: 19 輸出: 查詢成功! 輸入: 14 輸出: 1 2 3 4 5 6 7 8 9 11 12 13 19 16 */
測試