二叉排序樹的操作(建立、插入、刪除和查詢)
阿新 • • 發佈:2019-01-01
二叉排序樹的建立、插入、刪除和查詢
#include <stdio.h> #include <stdlib.h> typedef struct node { int key; struct node *lchild,*rchild; }BSTNode; //二叉排序樹插入操作遞迴演算法 BSTNode *InsertBST1(BSTNode *T, int key) { BSTNode *p, *q = T; //p為待插入的新結點 p = (BSTNode *)malloc(sizeof(BSTNode)); p->key = key; p->lchild = p->rchild = NULL; if(T == NULL) //原樹為空 T = p; //新插入的結點為新的根 //原樹非空時將新結點p作為q的左孩子或右孩子插入 else { if(key == q->key) return T; if(key < q->key) { if(q->lchild ==NULL) q->lchild = p; else InsertBST1(q->lchild, key); } if(key > q->key) { if(q->rchild ==NULL) q->rchild = p; else InsertBST1(q->rchild, key); } } return T; } ////二叉排序樹插入操作非遞迴演算法 BSTNode *InsertBST2(BSTNode *T, int key) { BSTNode *f, *p = T; //查詢插入位置 while(p) { if(key == p->key) return T;//無須插入 f = p;//記錄訪問的結點 if(key < p->key) p = p->lchild; else p = p->rchild; //若key<p->key,則在左子樹中查詢,否則在右子樹中查詢 } //p為待插入的新結點 p = (BSTNode *)malloc(sizeof(BSTNode)); p->key = key; p->lchild = p->rchild = NULL; if(T == NULL) //原樹為空 T = p; //新插入的結點為新的根 //原樹非空時將新結點q作為p的左孩子或右孩子插入 else { if(key < f->key) f->lchild = p; else f->rchild = p; } return T; } //二叉排序樹刪除操作 void DelBST(BSTNode *T,int key) { BSTNode *p = T, *f, *q, *s; while(p) { if(p->key == key) break; //找到關鍵字為key的結點 f=p;//記下關鍵字key節點的父節點 p=(key < p->key)? p->lchild : p->rchild;//分別在*p的左、右子樹中查詢 } if(!p) return;//二叉排序樹中無關鍵字為key的結點 if(p->lchild == NULL && p->rchild == NULL)//p無左子樹無右子樹 { if(p == T) T = NULL;//刪除的是根節點 else if(p == f->lchild) f->lchild = NULL; else f->rchild = NULL; } else if(p->lchild == NULL && p->rchild != NULL)//p無左子樹有右子樹 { if(f->lchild == p) f->lchild = p->rchild; else f->rchild = p->rchild; } else if(p->rchild == NULL && p->lchild != NULL)//p有左子樹無右子樹 { if (f->lchild == p) f->lchild = p->lchild; else f->rchild = p->lchild; } else if(p->lchild != NULL && p->rchild != NULL)//p既有左子樹又有右子樹 { q = p; s = p->lchild;//轉左 while(s->rchild) {//然後向右到盡頭 q = s; s = s->rchild;//s指向被刪節點的“前驅”(中序前驅) } p->key = s->key;//以p的中序前趨結點s代替p(即把s的資料複製到p中) if(q != p) q->rchild = s->lchild;//重接q的右子樹 else q->lchild = s->lchild;//重接q的左子樹。 } } //建立二叉排序樹 BSTNode *CreateBST() { BSTNode *T = NULL; //初始時T為空樹 int key; printf("請輸入一系列數,以0結尾:"); while(1) { scanf("%d", &key);//讀入一關鍵字 if(key == 0) break;//假設key=0是輸入結束標誌 else T = InsertBST1(T, key); //使用遞迴演算法,將key插入二叉排序樹T,改為 T = InsertBST2(T, key);為非遞迴插入演算法 } return T; //返回建立的二叉排序樹的根指標 } //二叉排序樹查詢遞迴演算法 int BSTsearch1(BSTNode *T, int data) { BSTNode *p = T; if(!p) return 0; else if(p->key == data) return 1; else if(p->key > data) return BSTsearch1(p->lchild, data); else return BSTsearch1(p->rchild, data); } //二叉排序樹查詢非遞迴演算法 int BSTsearch2(BSTNode *T, int data) { BSTNode *p = T; while(p) { if(p->key == data) return 1; p = (p->key > data)? p->lchild : p->rchild; } return 0; } //中序遍歷得到的是一個有序的序列,實現了排序功能 void Inorder(BSTNode *T) { if(T) { Inorder(T->lchild); printf("%d ",T->key); Inorder(T->rchild); } } int main() { BSTNode *T = NULL; int data1,data2; T = CreateBST(); printf("以上述數建立的二叉排序樹,中序遍歷的結果:"); Inorder(T); printf("\n輸入待搜尋的資料data1="); scanf("%d", &data1); //遞迴演算法查詢 if(BSTsearch1(T, data1)) printf("%d存在\n"); else printf("%d不存在\n"); //非遞迴演算法查詢 if(BSTsearch2(T, data1)) printf("%d存在"); else printf("%d不存在"); printf("\n輸入待刪除的資料data2="); scanf("%d", &data2); DelBST(T,data2); printf("刪除後的二叉排序樹,中序遍歷的結果:"); Inorder(T); return 0; }
對於刪除操作的一點小改動的程式
//二叉排序樹刪除操作 void DelBST(BSTNode *T,int key) { BSTNode *p = T, *f, *q, *s; while(p) { if(p->key == key) break; //找到關鍵字為key的結點 f=p;//記下關鍵字key節點的父節點 p=(key < p->key)? p->lchild : p->rchild;//分別在*p的左、右子樹中查詢 } if(!p) return;//二叉排序樹中無關鍵字為key的結點 if(p->lchild == NULL && p->rchild == NULL)//p無左子樹無右子樹 { if(p == T) T = NULL;//刪除的是根節點 else if(p == f->lchild) f->lchild = NULL; else f->rchild = NULL; } else if(p->lchild == NULL && p->rchild != NULL)//p無左子樹有右子樹 { if(f->lchild == p) f->lchild = p->rchild; else f->rchild = p->rchild; } else if(p->rchild == NULL && p->lchild != NULL)//p有左子樹無右子樹 { if (f->lchild == p) f->lchild = p->lchild; else f->rchild = p->lchild; } else if(p->lchild != NULL && p->rchild != NULL)//p既有左子樹又有右子樹 { q = p; s = p->lchild; if(s->rchild == NULL) { q->key = s->key; q->lchild = s->lchild;//重接q的左子樹 } else { while(s->rchild) {//然後向右到盡頭 q = s; s = s->rchild;//s指向被刪節點的“前驅”(中序前驅) } p->key = s->key;//以p的中序前趨結點s代替p(即把s的資料複製到p中 q->rchild = s->lchild;//重接q的右子樹 } } }