1. 程式人生 > >二叉連結串列(鏈式二叉樹)的非遞迴建立

二叉連結串列(鏈式二叉樹)的非遞迴建立

這裡我採用的是先序非遞迴建立二叉樹。思路很簡單:
首先要有一個結點陣列。
1.取第一個結點,是否為空,不是就作為樹根,壓棧,是空則樹根為空,結束。
2.取下一個結點a。
3.取棧頂結點b,如果棧頂結點沒有左孩子,那麼b->lchild=a,如果棧頂結點b有左孩子沒有右孩子,那麼 b->rchild=a,如果棧頂結點左孩子右孩子都存在,那麼彈棧,重複3。
4.重複2-4,直到棧空,或者所有結點都被加入樹中。

那麼問題來了,怎麼判斷棧頂結點是否存在左孩子和右孩子呢。比較簡單的想法就是增設一個標誌位,藉助標誌位來判斷。不過在寫樹的時候,顯然還是希望每個結點不要多出來一些奇怪的變數,只在建樹的時候有用,其它地方都沒有用處。那麼是否可以通過左右孩子指標域的值來判斷呢,答案是肯定的。我們可以在建立每個結點的時候將這些左右孩子指標回指自身,以此來代表這些結點的左右孩子是否存在,操作易於實現,判斷起來也很方便。
下貼程式碼:
我這裡假設每個結點都用一個字元來代表,’#’就代表這個結點為空。然後這一串字元就構成了串 nodes,作為函式的輸入。當然可以改變這種方式,讀者只需稍作修改。

#include <iostream>
#include <string>
#include <stack>
using namespace std; 

typedef struct BiTreeNode{
    char ch;
    BiTreeNode *lchild;
    BiTreeNode *rchild;
}BiTreeNode,*BiTree; 

BiTreeNode* CreateTree(string nodes){//構造二叉連結串列的函式 
    //先序非遞迴法構造鏈式二叉樹  
    stack<BiTreeNode*>
stack1; BiTreeNode *pd1,*pd2;//指向二叉樹結點的指標 bool flag; int n=nodes.size(); BiTreeNode *root=NULL; if(nodes[0]!='#'){//不是空樹 pd1=new BiTreeNode; pd1->lchild=pd1;//左孩子指標回指 pd1->rchild=pd1;//右孩子指標回指 pd1->ch=nodes[0]; root=pd1; int k=0; stack1.push(pd1);//樹根入棧
while(!stack1.empty()&&k!=n-1){ flag=false; if(nodes[++k]!='#'){ pd2=new BiTreeNode; pd2->ch=nodes[k]; pd2->lchild=pd2;//左孩子指標回指 pd2->rchild=pd2;//右孩子指標回指 flag=true; }else pd2=NULL; pd1=stack1.top(); while(pd1->lchild!=pd1&&pd1->rchild!=pd1){//找到沒有左右孩子的棧頂結點 stack1.pop(); pd1=stack1.top(); } if(pd1->lchild==pd1)//沒有左孩子 pd1->lchild=pd2; else pd1->rchild=pd2; if(flag)//pd2不是空指標 stack1.push(pd2);//pd2入棧 } } return root; } void preordertraverse(BiTree T){//先序遍歷 if(T){ cout << T->ch; preordertraverse(T->lchild); preordertraverse(T->rchild); } } void inordertraverse(BiTree T){//中序遍歷 if(T){ inordertraverse(T->lchild); cout << T->ch; inordertraverse(T->rchild); } } int main(){ string nodes; cin >> nodes; BiTree T=CreateTree(nodes); preordertraverse(T);//先序遍歷 cout << endl; inordertraverse(T);//中序遍歷 cout << endl; return 0; }

附一張執行結果圖:
輸入:AB#DF###C#E##
輸出:
這裡寫圖片描述

原本我打算將樹寫成一個模板類,在寫建構函式時發現,雖然遞迴建立樹很簡潔,但是寫在建構函式裡很不方便,於是自己在紙上畫圖,想出了這個演算法。其中恐有訛誤,如果發現請聯絡作者指正。

相關推薦

連結串列建立

這裡我採用的是先序非遞迴建立二叉樹。思路很簡單: 首先要有一個結點陣列。 1.取第一個結點,是否為空,不是就作為樹根,壓棧,是空則樹根為空,結束。 2.取下一個結點a。 3.取棧頂結

連結串列儲存的基本操作

Clist.h #ifndef CLIST_H_ #define CLIST_H_ typedef struct _tag_CListNode {struct _tag_CListNode* next; }CListNode; typedef void CList; CLi

連結串列棧、佇列、的C簡要實現

/*單鏈表簡要實現 * * */ #include <stdio.h> #include <stdlib.h> struct Node; typedef struct

UVa 122 Trees on the level建立和層次遍歷

構建 void target .net color 鏈接 struct failed div 題目鏈接: https://cn.vjudge.net/problem/UVA-122 1 /* 2 問題 3 給出每個節點的權值和路線,輸出該二叉樹的層次遍歷序列。

玩轉連結串列 20 分

玩轉二叉連結串列 (20 分) 先序建立二叉樹的二叉連結串列 設計程式,按先序建立二叉樹的二叉連結串列;然後先序、中序、後序遍歷二叉樹。 輸入格式: 按先序輸入一棵二叉樹。二叉樹中每個結點的鍵值用字元表示,字元之間不含空格。注意空樹資訊也要提供,以#字元表示空樹。 輸出格式:

採用連結串列儲存,複製的演算法的應用

二叉樹採用二叉連結串列儲存,試寫出複製一棵二叉樹的演算法。 話不多說上程式碼: #include<stdio.h> #include<stdlib.h> typedef struct BiTnode   {   &

LeetCode-114.展開為連結串列相關話題:深度優先

給定一個二叉樹,原地將它展開為連結串列。 例如,給定二叉樹 1 / \ 2 5 / \ \ 3 4 6 將其展開為: 1 \ 2 \ 3 \ 4 \ 5

c語言實現連結串列後序遍歷

演算法思想 因為後序遍歷是先訪問左子樹,再訪問右子樹,最後訪問根節點。當用棧實現遍歷時,必須分清返回根節點時,是從左子樹返回的還是從右子樹返回的。所以使用輔助指標r指向最近已訪問的結點。當然也可以在節點中增加一個標誌域,記錄是否已被訪問。 #include<iost

擴充套件的先序遍歷序列建立連結串列方式儲存的,後序遍歷

1. 請根據使用者輸入的“擴充套件的先序遍歷序列”(用小圓點表示空子樹),建立以二叉連結串列方式儲存的二叉樹,然後寫出後序遍歷該二叉樹的非遞迴演算法,並將對應的程式除錯執行通過。 #include<stdio.h> #include<std

實現前序、中序、後序

一、結合棧的方式實現,先讓右孩子入棧,再讓左孩子入棧。棧為空後,結束遍歷。 標頭檔案.根據具體的函式名自己建立,另外需要使用棧,引用棧的標頭檔案   stack.h # pragma oncee # include<stdio.h> # include<s

遍歷先序、中序、後序和層序遍歷

[前文] 二叉樹的非遞迴遍歷有 先序遍歷、中序遍歷 、後續遍歷 和 層序遍歷。 非遞迴演算法實現的基本思路:使用堆疊。而層序遍歷的實現:使用佇列。 如下圖所示的二叉樹:      前序遍歷順序為:ABCDE  (先訪問根節點,然後先序遍歷其左子樹,最後先序遍歷

C語言 的遍歷 多種演算法

//二叉樹遍歷 //作者:nuaazdh //時間:2011年12月1日 #include<stdio.h> #include<stdlib.h> #define OK 1 #define ERROR 0 #defi

遍歷前序中序後序C語言

前兩天做資料結構實驗,要求用非遞迴演算法遍歷二叉樹。只知道用棧來儲存資料,具體演算法還不太清楚。經過兩天的搜尋,看到網上很多種解法,很多解法都是用C++來寫的演算法,一直找不到用C語言寫的演算法,所以就總結了一下,用C寫出了一個遍歷二叉樹的三種非遞迴演算法。 前

LeetCode題解-144. Binary Tree Preorder Traversal前序遍歷

題目:Given a binary tree, return the preorder traversal of its nodes' values.Example:Input: [1,null,2,3] 1 \ 2 / 3 Outpu

遍歷 leetcode

利用資料結構-棧,佇列, 加上相應思路等完成。 leetcode練習,隔段時間敲幾次程式碼 非遞迴先序 #include <cstdlib> #include <iostream> #includ

隊列存儲結構

eat 結構 int type logs nsh com body tps 隊列的鏈式存儲結構不常用 同理,實際上也可以用一個單鏈表實現 插入、刪除分別在鏈表兩頭進行,即插入在表尾(rear),刪除在表頭(front) 圖解如下: 0、結構初始化 struct Lis

存儲結構

特性 null while raw 分享 leet source strlen http 堆棧:具有一定操作約束的線性表,只能在一端作插入、刪除 具有後入先出的特性(Last In First Out) 分順序存儲結構、鏈式存儲結構兩種形式 堆棧的順序存儲結構 通常

LeetCode 25. k個一組翻轉連結串列Reverse Nodes in k-Group

題目描述   給出一個連結串列,每 k 個節點一組進行翻轉,並返回翻轉後的連結串列。 k 是一個正整數,它的值小於或等於連結串列的長度。如果節點總數不是 k 的整數倍,那麼將最後剩餘節點保持原有順序。 示例 : 給定這個連結串列:1->

資料結構 筆記-6 先序遍歷

如下這棵二叉樹的先序遍歷結果為:ABDEFPC 針對於上面的這棵二叉樹,結合程式碼,講述遍歷過程: #include <stdio.h>#include <malloc.h> //#define ElemType

資料結構 筆記-7 中序遍歷

二叉樹的 非遞迴 中序遍歷 //#define ElemType char   typedef char ElemType; 結點中存放的資料的型別的定義