插入:從根結點開始,沿樹降低。指針x跟蹤這條路徑,而y始終指向x的父結點。根據key[z]與key[x]的比較結果,決定向左向右轉。直到x成爲NIL爲止。這個NIL所佔位置及咱們想插入z的地方,y即爲z的父結點。算法
刪除:以指向z的指針爲參數,考慮三種狀況。若z沒有子女,則修改其父結點p[z],是NIL爲其子女;若是結點z只有一個子女,則能夠經過在其子結點與父結點之間創建一條鏈來刪除z。若是結點z有兩個子女,先刪除z的後繼y(它沒有左子女),再用y的內容來替代z的內容。數據結構
void treeInsert(NODE *z) { NODE *y = NULL; NODE *x = root; while (x != NULL) { y = x; if (z->key < x->key) x = x->l; else x = x->r; } z->p = y; if (y == NULL) root = z; else { if (z->key < y->key) y->l = z; else y->r = z; } } NODE* treeDelete(NODE* z) { NODE *y, *x; if (z->l == NULL || z->r ==NULL) y = z; else y = treeSuccessor(z); if (y->l != NULL) x = y->l; else x = y->r; if (x != NULL) x->p = y->p; if (y->p == NULL) root = x; else { if (y == y->p->l) y->p->l = x; else y->p->r = x; } if (y != z) { z->key = y->key; } return y; }
12.3-1 給出過程TREE-INSERT的一個遞歸版本。性能
void insert(NODE *rt, NODE *z,NODE *pa = NULL) { if (rt == NULL) { z->p = pa; z->l = z->r = NULL; if (pa == NULL) root = z; else { if (z->key < pa->key) pa->l = z; else pa->r = z; } return; } if (z->key < rt->key) insert(rt->l,z,rt); else insert(rt->r,z,rt); }
12.3-2 假設咱們經過反覆插入不一樣的關鍵字的作法來構造一棵二叉查找樹。論證:爲在樹中查找一個關鍵字,所檢查的結點數等於插入該關鍵字時所檢查的結點數+1。指針
插入時的比較與查找時的比較幾乎徹底相同,惟一區別爲查找時要多檢查插入時的結點。code
12.3-3 能夠這樣來對n個數進行排序:先構造一棵包含這些數的二叉查找樹(重複應用TREE-INSERT來逐個地插入這些數),而後按中序遍從來輸出這些數。這個排序算法的最壞狀況和最好狀況運行時間怎樣?blog
最壞狀況,二叉樹退化成鏈,則構造O(n^2),遍歷O(n),運行時間O(n^2)。排序
最好狀況,二叉樹平衡,構造O(nlogn),遍歷O(n),運行時間O(nlogn)。遞歸
12.3-4 假設另有一種數據結構中包含指向二叉查找樹中某結點y的指針,並假設用過程TREE-DELETE來刪除y的前驅z。這樣作會出現哪些問題?如何改寫TREE-DELETE來解決這些問題?ip
有可能指向y的指針已被刪除,而y的值已被複制到z。class
將y指向父結點子結點的指針改成與z相同,並改變z的父結點指向z的指針與子結點指向父親的指針。
12.3-5 刪除操做是能夠交換的嗎?說明爲何是的,或給出一個反例。
12.3-6 當TREE-DELETE中的結點z有兩個子結點時,能夠將其前驅拼接掉。有些人提出了一種公平的策略,即爲前驅和後繼結點賦予相同的優先級,從而能夠獲得更好的經驗性能。那麼,應該如何修改TREE-DELETE來實現這樣一種公平的策略?