二叉樹的非遞迴插入和遍歷

2021-07-12 04:07:40 字數 3186 閱讀 9703

二叉樹是一種常見的適合使用遞迴進行遍歷的資料結構,但是如同絕大多數遞迴操作,二叉樹的遍歷也可以使用非遞迴的方式來實現,研究二叉樹的非遞迴實現有助於更好的掌握二叉樹的結構和使用方式。

遞迴好是好,只是太無腦。只會用遞迴解自迴圈資料就像只會用方程組解應用題那樣,喪失了對資料結構本質的解析能力。

上圖所示是乙個簡單的二叉樹的示意圖。如果要對上述二叉樹進行中序遍歷,我們應該先對根節點的左子樹(如果有)進行遍歷,再對根節點進行操作,最後對右子樹(如果有)進行遍歷。對每個左子樹和右子樹的每個節點都進行遞迴式上述操作即可實現對所有節點的遍歷。這用遞迴很容易實現,但是如果不使用遞迴呢?

假設節點類定義如下:

class bstnode

;bstnode::bstnode(int v)

bstnode::~bstnode()

插入首先來看看比較簡單的插入操作:只需要從上到下搜尋到符合要求的節點即可,不需要返回曾經搜尋過的節點來對它的另乙個子樹進行遍歷。這樣我們就不需要記錄曾經訪問過哪些節點,只需要在每次迴圈中將符合要求的下乙個節點的位址儲存下來作為下一次迴圈需要訪問的節點即可,如此迴圈直到找到對應的位置後將資料插入。

**如下:

void bst::add(int value)

auto temp = root;

while (temp!=nullptr)

//當前節點左孩子不為空則將左孩子節點作為下個迴圈的節點

else

temp = temp->left;

}//待插入值大於當前節點值

else

//當前節點右孩子不為空則將右孩子節點作為下個迴圈的節點

else

temp = temp->right;}}

}

很簡單,乙個迴圈乙個指標即可解決問題。

遍歷

插入操作很簡單,但是如果是遍歷呢?對於遍歷操作而言可不想插入操作那樣僅僅找到符合要求的位置即可,因為需要將所有節點都遍歷到,所以除了只有左孩子的樹,都會需要返回曾經訪問過的節點再次對其進行訪問。這時候該怎麼辦呢?

如下圖所示:在一次中序遍歷中,我們會從根節點先一路訪問左子樹找到第乙個沒有左子樹的節點並對其進行操作,然後對其右子樹(如果有)進行操作,對其右子樹操作結束後再返回其父節點進行操作。

將上次遍歷的父節點作為當前節點進行操作後再對其右子樹(如果有)進行遍歷,然後再將其父節點作為下次訪問的節點,如此迴圈直至結束:

如上圖所示,由於對於某些節點進行訪問之後需要回到曾經訪問過的節點,所以需要知道當前訪問的節點是首次訪問還是第二次訪問,這時我們就需要乙個棧來對資料進行儲存了:最後乙個入棧的是最下層的節點也就是需要最先訪問的節點。

對於每個節點,在第一次訪問時,如果它有左孩子,則將左孩子推入棧,然後將其左孩子作為當前節點進入下一次迴圈;如果它是第一次訪問且沒有左孩子或者是二次訪問則對該節點進行操作,操作結束後進行出棧操作(將已操作國的節點從棧中刪除),如果它有右孩子則將右孩子節點入棧並將其作為下一次訪問的當前節點並進入下一次操作,如果沒有右孩子則將父節點作為下次訪問的節點。

由於每次迴圈都將下次要訪問的節點先入棧,則如果棧頂節點等於當前節點則說明是首次訪問,如果棧頂節點不等於當前節點則說明是二次訪問,而棧為空則說明已經遍歷完所有節點。

首先將根節點入棧,並將根節點作為當前節點。

**如下:

void bst::inorderptr()

//否則該節點就是需要操作的當前節點

else

//否則對棧頂節點出棧

else}}

}

測試測試**:

bst

bst;

bst.add(10);

bst.add(8);

bst.add(4);

bst.add(2);

bst.add(5);

bst.add(6);

bst.add(20);

bst.add(13);

bst.add(16);

bst.inorderptr();

結果:2 4

5 6

8 10

13 16

20 從結果看,上述操作復合中序遍歷的結果。

#include "stdafx.h"

#include

#include

using

namespace

std;

class bstnode

;bstnode::bstnode(int v)

bstnode::~bstnode()

class bst

;bst::bst()

bst::~bst()

void bst::add(int value)

auto temp = root;

while (temp!=nullptr)

//當前節點左孩子不為空則將左孩子節點作為下個迴圈的節點

else

temp = temp->left;

}//待插入值大於當前節點值

else

//當前節點右孩子不為空則將右孩子節點作為下個迴圈的節點

else

temp = temp->right;}}

}void bst::inorderptr()

//否則該節點就是需要操作的當前節點

else

//否則對棧頂節點出棧

else}}

}

#include "stdafx.h"

#include "bst.h"

int _tmain(int argc, _tchar* argv)

二叉樹遞迴遍歷和非遞迴遍歷

用遞迴和非遞迴實現二叉樹的前序遍歷 中序遍歷和後序遍歷並列印出相應結果。private class treenode 在遞迴呼叫時候系統自動給我們建立棧來儲存資料,而使用非遞迴時候需要我們自己實現棧來儲存資料。遞迴實現前序遍歷public void preorder treenode root sy...

二叉樹遍歷(遞迴和非遞迴)

二叉樹的中序遍歷 二叉樹的後序遍歷 測試二叉樹的節點定義如下 節點 二叉樹的前序遍歷順序為 根左右。如下圖所示,前序遍歷順序為 1245367。遞迴 public static void preorder treenode root system.out.print root.val preorde...

二叉樹的遞迴遍歷和非遞迴遍歷

二叉樹是一種基本的資料結構,在程式設計師面試中經常會被考察。其中按一定順序遍歷所有節點是最基本的操作,很多知名的面試題目,例如求二叉樹的深度 求出和為某一值的路徑等等,本質上都是遍歷的變種。本文試圖從遞迴和非遞迴的角度來考察一下遍歷的演算法。遍歷定義 在二叉樹中,每乙個節點都有左右兩個子節點 子節點...