不允許開闢新的節點,只是改變指標的轉向,將一顆標準的bst轉化為乙個雙向鍊錶,返回雙向鍊錶的頭指標
測試用例描述:75
9-28 10
3 12
1這棵二叉查詢樹轉化為雙向鍊錶的操作結果是:-2 --1 --3 --5 --7 --8 --9 --10 --12
本博主的bst總結詳解
這裡我們先考慮bst 的性質,bst作為一顆高效的二叉查詢樹,性質如下:
1.空樹
2.非空樹且左子樹節點鍵值均小於根節點的鍵值,右子樹所有的節點的鍵值均大於根節點的鍵值
左右子樹均為一顆bst
那麼再轉化成雙向鍊錶的時候,我們根據題意只能通過改變指標來進行操作,當然操作的前提是比該節點的鍵值小的節點已經存在於有序的雙向鍊錶中,這樣子進行遞迴的定義我們就會發現,我們要保證是有序的雙向鍊錶,那麼我們根據bst 的性質完全可以通過所謂的中序遍歷來實現,在中序遍歷的時候我們隊當前的根節點的指標域進行操作就可以了
準備操作
首先我們要開闢兩個輔助的指標來幫助我們根號的控制目前已經有序的雙向鍊錶
1.head指標:作為整個雙向鍊錶的頭結點(只有兩種狀態,空或者非空,空代表目前雙向鍊錶不存在任何乙個有序的節點,非空代表目前的雙向鍊錶中至少有乙個有序的節點)
2.listtail指標:顧名思義,listtail時終止向目前的雙向鍊錶中的最後乙個元素(只有兩個狀態,空和非空,空代表目前雙向鍊錶不存在任意乙個有序的節點,非空代表至少存在乙個有序的節點),實際上我們發現listtail和head的狀態實際上是同步的,那我們為什麼要新引入乙個listtail指標呢,其實這完全是為了節省時間,如果我們不引入這個指標記憶體空間,那麼我們就必須環肥o(n)複雜度的使勁去遍歷一遍整個目前有序的雙向鍊錶,所謂空間換時間,相對而言,這麼做是非常划算的
指標變化
(p代表當期嗎遍歷到的節點,方便後續我們的被描述)
1.如果head為空,那麼我們令head只想當前遍歷到的節點,然後listtail同樣指向這個節點
2.如果head不為空,說明listtail目前有確定指向,那麼我們將listtail->right=p,p->left=listtail,listtail=p(最後一步的作用實際上是擴充套件我們的listtail,保證期時終止向最後乙個節點);
因為在博主上一期的資料結構專題中,已經討論過bst並且封裝了bst的**,這次我就直接拿來呼叫了,強調一點,對於cbst我是考慮了公有繼承,所以之後要用到root成員,所以bst我們這裡設定成保護型別(實際上c++**中,一旦要被繼承的物件中的成員我們都是設定成保護型別的)
具體的操作和解釋在**中進行注釋
#include"iostream"
#include"cstdio"
#include"cstdlib"
using namespace std;
typedef struct node
point;
class errorsame
;
class bst
virtual ~bst()
void add(int);
void del(int);
point* find(int);
void clear(point*);
void preorder(point*);
void midorder(point*);
void aftorder(point*);
void rankorder();
point* returnroot()
protected:
point* root;
int num;
};
void bst::clear(point* p)
} void bst::add(int p)
else
if(w!=null) k=w;
} if(k->key>p)
else
num++;
} catch(errorsame e)
else
if(now==null)
else
z->left=k->right;
k->left=root->left;
k->right=root->right;
root=k;
} }
free(help);
} else if(now->right==null)
else
else
if(father->left==now)
else
} }
}
point* bst::find(int p)
}
void bst::preorder(point* p)
} void bst::midorder(point* p)
} void bst::aftorder(point* p)
} void bst::rankorder()
for(int i=1;i<=tail-1;i++) printf("%d ",queue[i]->key);
} class cbst:public bst
virtual ~cbst() //這裡就不再贅語為什麼用虛析構函式了
root=null; //很尷尬,我的虛析構函式知識點忘了,所以這裡手工將root設定成null,防止指標玄關的錯誤發生,尷尬,繼續去複習指標玄關的知識點去
} void visit(point*); //中序遍歷
void change(point*); //中序遍歷中對指標的進行的節點指標操作
void scan(); //程式正確性與否的測試**段
private:
point* head;
point* listtail;
};void cbst::visit(point* p) }
void cbst::change(point* p)
else }
void cbst::scan()
cout<
微軟面試100題 001
1.把二元查詢樹轉變成排序的雙向鍊錶 題目 輸入一棵二元查詢樹,將該二元查詢樹轉換成乙個排序的雙向鍊錶。要求不能建立任何新的結點,只調整指標的指向。10 6 14 4 8 12 16 轉換成雙向鍊錶 4 6 8 10 12 14 16。struct bstreenode 建立二叉查詢樹 includ...
微軟面試百題007 鍊錶相交
給出倆個單向鍊錶的頭指標,比如h1,h2,判斷這倆個鍊錶是否相交。為了簡化問題,我們假設倆個鍊錶均不帶環。問題擴充套件 1.如何判斷鍊錶存在環 2.如果需要求出倆個鍊錶相交的第乙個節點列?1.如何判斷鍊錶帶環 我們加入兩個指標,乙個快指標,乙個慢指標,快指標一次前進2個單位,慢指標一次前進乙個單位 ...
微軟面試百題009 按詞反轉句子
翻轉句子中單詞的順序。題目 輸入乙個英文句子,翻轉句子中單詞的順序,但單詞內字元的順序不變。句子中單詞以空格符隔開。為簡單起見,標點符號和普通字母一樣處理。例如輸入 i am a student.則輸出 student.a am i 棧 我們先將句子的內容儲存下來,然後開闢乙個棧,以單詞為單位不斷的...