オーダートラバーサルの間と後に、前のバイナリツリーを達成するためにスタック
あなたは、コードの3行のみの際、注文横断した後、前のバイナリツリーを達成するために再帰を使用している場合は場所を変更する必要があるが、それはスタックを使用する場合はるかに興味深いものを書くことになります
その左側のサブツリーのルート間の出力の優先順位
グラフTD 1((ルート))···2((左サブツリー))。3. 1 ---((右の部分木))
トラバーサル | 出力の優先順位 |
---|---|
先序 | ルート>左のサブツリー>右部分木 |
順番に | 左サブツリー>根>右部分木 |
オーダー後 | 左サブツリー>右の子>ルート |
使用規則をスタック
スタックポインタ内の要素は、ノードを指しています
- 唯一のトップ要素点ノードの内容が出力されます
- 便利な、あまりにも多くのノードを覚えていません
- ノードのコンテンツポインタがすぐにポップした後、出力ノードに向け
- 繰り返し出力ノードを避けます
- ノードポインタ点の左右サブツリーが使用されていない場合は、スタックへのポインタは、(横断しないか、空でない)場合、次にポイントは左右のサブツリーは、次いでスタックポインタになり、後に方向付け初期の出力ノードポインタスタック
- スタックは、情報の損失を避けるためである、順序がスタックの特徴である(最終)
- ルートノードにスタックポインタを初期化するだけ
- トラバーサルの基本的なパラメータとして、多くの場合、ルートノード
- スタックが空である場合には、エンドを通過するとき
- すなわち、全てがトラバースされたノード(図2を参照すると、図3に示すようにすることによって導出することができます)
アルゴリズム
問題は完全に3つのノードを有するまで低減されるように、それはスタックポインタでサブツリーのルート又は表現程度であるかどうかは、「ノード」と同じであるので、我々は、各サブツリー約缶バイナリツリーの出力
単純化された基礎で、その後、特別な事情のルールを達成することができ考えます
一般的なロジックの端を横切るときに、スタックが空である場合、唯一のルートノードを初期化し、スタックポインタ
予約限定!
導出
グラフTD 1((ルート))···2((左サブツリー))。3. 1 ---((右の部分木))
- 出力順:ルート - >左のサブツリー - >右部分木
- ルール説明はコンバイン
- 優先出力ルートノードルール2と併せて得ることができる、直接出力にスタックポインタの接合、スタックポインタは直ちに(バックアップが必要とされる)をスタックします
- スタック3にスタックポインタルールと併せて得ることができる、第一のスタック及び左サブツリーの右サブツリーをポインタ左サブツリー及びバックアップノードの右サブツリーがスタックに向けられる(空でありません)
- 結論として、法律から引き出すことができます
- 第1の出力ノードスタックポインタ
- ポップ・スタック・ポインタ(スタック・ポインタ・バックアップ、またはサブツリーの情報の損失)
- スタックの右サブツリーにバックアップノードポインタ(右サブツリーポインタがnullでない場合)
- スタックの左の部分木へのバックアップノードポインタ(左の部分木ポインタがnullでない場合)
- 戻るステップ1へ
達成するためのC ++コード
void preorder_travel() {
if (root == NULL)
return;
std::stack<Node*> s;
s.push(root);//根指针入栈
while (!s.empty())
{
std::cout << s.top()->data << " ";//输出栈顶指针指向的结点
Node* temp = s.top();//备份栈顶指针
s.pop();//栈顶指针出栈
if (temp->R != NULL) s.push(temp->R);//备份指向结点右子树不为空则将其压入栈
if (temp->L != NULL) s.push(temp->L);//备份指向结点左子树不为空则将其压入栈
}
}
予約限定!
導出
グラフTD 1((ルート))···2((左サブツリー))。3. 1 ---((右の部分木))
- 出力順序:左のサブツリー - >ルート - >右部分木
- ルール説明はコンバイン
- 左ルートに続いて左のサブツリー優先出力のサブツリー、しかし、サブツリーは、直接出力することはできませんので、彼らは木の左の子ノードにスタックポインタを検索する...あなたは何の結び目に何の左部分木を見つけなくなるまで点は、出力ノード(ルートノード)、ルール2に関連して導出することができる、ノードポインタの左の部分木がヌルになるまでスタックを指しスタック指す左サブツリーのノードポインタ、出力に繰り返しノードは、スタックポインタのスタック(バックアップが必要とされます)
- ステップ1は常に、左サブスタックポインタサブツリーのノードを指すスタックポインタから引き出され、そして、出力ノードを指すルートノード(現在のスタックポインタ)にサブツリー(元のスタックポインタ)を残すことができ、ルールと一緒に2を描画することができる(スタックの出力後に以前のバックアップ出力に)繰り返して出力ノードスタックポインタ
- 出力スタックポインタ、ルール3は、と一緒に得ることができるノードの右サブツリーは、それはスタックにプッシュされた場合、バックアップ・ポイントの存在
- 右部分木のプッシュ(スタックポインタは常に左の子ノードツリーへの二次スタックポインタである)2つの前提条件を破るために、2を停止し、
- 出力スタックポインタ、ルール3は、と一緒に得ることができるノードの右サブツリーは、それはスタックにプッシュされた場合、バックアップ・ポイントの存在
- 戻るステップ1へ
- 結論として、法律から引き出すことができます
- スタックポインタのノード左サブツリートップがヌルになるまでスタックポインタ左サブツリーのノードに繰り返し、その後、出力ノード、スタックポインタスタックは、(ポインタバックアップ、情報が失われたり左右サブツリーれるスタック)
- ノードのバックアップ右サブツリーが空でなくなるまで、繰り返し出力ノード(スタックを出力する前後の出力バックアップ)へスタックポインタ、右サブツリースタック、バック
達成するためのC ++コード
void inorder_travel() {
if (root == NULL)
return;
std::stack<Node*> s;
s.push(root);//根指针入栈
while (!s.empty())
{
while (s.top()->L != NULL)//重复将栈顶指针指向结点的左子树压栈,直到栈顶指针指向结点的左子树为空
{
s.push(s.top()->L);
}
while (!s.empty())//重复检查
{
std::cout << s.top->data << " ";//输出栈顶指针指向的结点
Node* temp = s.top();//备份栈顶指针
s.pop();//栈顶指针出栈
if (temp->R != NULL) {//如果栈顶指针指向的结点右子树不为空,则将其右子树入栈,退出检查
s.push(temp->R);
break;
}
}
}
}
後順
導出
グラフTD 1((最上位ノードをスタック))···2((左サブツリー))。3. 1 ---((右の部分木))
- 出力順序:左のサブツリー - >右部分木 - >ノードスタック
- ルール説明はコンバイン
- 左サブツリー優先出力、右のサブツリーを続いたが、直接出力サブツリーをすることはできません、それは木の左部分木の左の子ノードにスタックポインタを検索されている...あなたは何の左部分木を見つけることはありませんまでノード2は、ルールに関連して導出することができるノードのポインタの左の部分木がヌルになるまでスタックを指し、左サブツリー・ノード・ポインタを指し示すスタックに繰り返します
- ステップ1は、スタック・ポインタによって得ることができる常にノードにサブツリー二次スタックポインタ点を左、右サブツリーにサブツリー(元のスタックポインタ)に残っている(現在スタックポインタ右の子ノードを指し木)出力
- 繰り返しのステップ2前提でチェック
- 右の子ノードへのスタックポインタは、(直前の出力をマークするためにノードポインタを)横断した場合、出力スタックポインタ、スタックのポップ
- 右の子ノードツリーへのスタックポインタが空の場合は、出力スタックポインタ、スタックのポップ
- ノードの右の部分木にスタックポインタが空でない場合、配列は、右サブツリーをスタック出力から導出することができます
- 右部分木のプッシュ(スタックポインタは常に左の子ノードツリーへの二次スタックポインタである)2つの前提条件を破るために、2を停止し、
- 繰り返しのステップ2前提でチェック
- 戻るステップ1へ
- 結論として、法律から引き出すことができます
- 左サブツリーのノードにスタックポインタがヌルになるまでスタックポインタ左サブツリーのノードに繰り返し
- 右の子ノードへのスタックポインタがスタックノード右サブツリーに、スタックの最上位にスタック。そうでない場合、スタックポインタ横断または空の場合に繰り返し送信が決定されます
- 戻るステップ1へ
達成するためのC ++コード
void postorder_travel() {
if (root == NULL)
return;
std::stack<Node*> s;
s.push(root);//根指针入栈
while (!s.empty())
{
while (s.top()->L != NULL)//重复将栈顶指针指向结点的左子树压栈,直到栈顶指针指向结点的左子树为空
{
s.push(s.top()->L);
}
Node* last = NULL;//上一次遍历过的指针
while (!s.empty())//重复检查
{
if (s.top()->R==NULL||last==s.top()->R) {//如果栈顶指针指向结点的右子树为空或者遍历过
std::cout << s.top()->data << " ";//输出栈顶指向的结点
last = s.top();//更新指针last
s.pop();//栈顶指针出栈
}
else if(s.top()->R!=NULL)//如果栈顶指针指向的结点的右子树不为空
{
s.push(s.top()->R);//将右子树入栈
break;//退出检查
}
}
}
}
全体のコード
#include <iostream>
#include <stack>
template <typename T>
class BST {
public:
BST() :root(NULL) {};
~BST() {};
void insert(T data) {
Node* temp = new Node();
temp->L = NULL;
temp->R = NULL;
temp->data = data;
if (root == NULL) {
root = temp;
}
else {
Node* tracer = root;
while (true)
{
if (tracer->data >= data)
if (tracer->L == NULL) {
tracer->L = temp;
break;
}
else
tracer = tracer->L;
else
if (tracer->R == NULL) {
tracer->R = temp;
break;
}
else
tracer = tracer->R;
}
}
}
void preorder_travel() {
if (root == NULL)
return;
std::stack<Node*> s;
s.push(root);//根指针入栈
while (!s.empty())
{
std::cout << s.top()->data << " ";//输出栈顶指针指向的结点
Node* temp = s.top();//备份栈顶指针
s.pop();//栈顶指针出栈
if (temp->R != NULL) s.push(temp->R);//备份指向结点右子树不为空则将其压入栈
if (temp->L != NULL) s.push(temp->L);//备份指向结点左子树不为空则将其压入栈
}
}
void inorder_travel() {
if (root == NULL)
return;
std::stack<Node*> s;
s.push(root);//根指针入栈
while (!s.empty())
{
while (s.top()->L != NULL)//重复将栈顶指针指向结点的左子树压栈,直到栈顶指针指向结点的左子树为空
{
s.push(s.top()->L);
}
while (!s.empty())//重复检查
{
std::cout << s.top->data << " ";//输出栈顶指针指向的结点
Node* temp = s.top();//备份栈顶指针
s.pop();//栈顶指针出栈
if (temp->R != NULL) {//如果栈顶指针指向的结点右子树不为空,则将其右子树入栈,退出检查
s.push(temp->R);
break;
}
}
}
}
void postorder_travel() {
if (root == NULL)
return;
std::stack<Node*> s;
s.push(root);//根指针入栈
while (!s.empty())
{
while (s.top()->L != NULL)//重复将栈顶指针指向结点的左子树压栈,直到栈顶指针指向结点的左子树为空
{
s.push(s.top()->L);
}
Node* last = NULL;//上一次遍历过的指针
while (!s.empty())//重复检查
{
if (s.top()->R==NULL||last==s.top()->R) {//如果栈顶指针指向结点的右子树为空或者遍历过
std::cout << s.top()->data << " ";//输出栈顶指向的结点
last = s.top();//更新指针last
s.pop();//栈顶指针出栈
}
else if(s.top()->R!=NULL)//如果栈顶指针指向的结点的右子树不为空
{
s.push(s.top()->R);//将右子树入栈
break;//退出检查
}
}
}
}
private:
struct Node
{
Node* L;
Node* R;
T data;
};
Node* root;
};
int main(){
BST<int> b;
b.insert(2);
b.insert(4);
b.insert(1);
b.insert(5);
b.insert(3);
b.insert(0);
b.preorder_travel();
std::cout << std::endl;
b.inorder_travel();
std::cout << std::endl;
b.postorder_travel();
}