二叉樹順序結構和鏈式結構的相互轉換


設計思路

順序存儲結構和鏈式存儲結構的聯系

鏈式存儲結構的根節點的序號與其左右孩子的序號,在順序存儲結構中,存在這樣的關系: (注:根節點序號從零開始算,若從一開始算無需+1

\[左孩子的序號=根節點序號*2+1 \]

\[右孩子的序號=左孩子+1=根節點序號*2+2 \]

偽代碼

根據順序存儲結構和鏈式存儲結構之間序號的關系,設想如下偽代碼:

/*順序轉鏈式*/
BiTree Order_to_Chain(SqBtree T, int i)
{

	if (T[i] == '#') 
        {
                return 空;
        }
	新建二叉樹的結點BT;
	BT->data = T[i];
	遞歸遍歷左子樹;
	遞歸遍歷右子樹;
	return BT;
}
/*鏈式轉順序*/
void Chain_to_Order(BiTree T,int i)     //T為鏈式存儲結構的二叉樹

{            
	if (樹不空)
	{
		BT[i]=T->data;        //BT是為存儲順序存儲結構的二叉樹定義的字符串
		遞歸遍歷左子樹;
		遞歸遍歷右子樹;
	}
	else(如果該節點為空)
	{
		順序樹存入‘#’字符。
	}
}

重要代碼實現

順序轉鏈式

/*順序存儲結構轉鏈式*/
 BiTree Order_to_Chain(SqBtree T, int i) 
{
	BiTree BT;
	if (T[i] == '#')
	{
	    return NULL;
	}
	BT = new TNode;
	BT->data = T[i];
	BT->lchild = Order_to_Chain(T, 2 * i+1);
	BT->rchild = Order_to_Chain(T, 2 * i + 2);
	return BT;
}

鏈式轉順序

/*鏈式存儲結構轉順序*/
void Chain_to_Order(BiTree T,SqBtree &BT,int i)
{
	if (T)
	{
		BT[i] = T->data;
		Chain_to_Order(T->lchild, BT, 2 * i + 1);
		Chain_to_Order(T->rchild, BT, 2 * i + 2);
	}
	else
	{
		BT[i] = '#';
	}
}

代碼運行結果及分析

對於這棵二叉樹:

它的前序遍歷結果為ABDEC,中序遍歷結果為DEBAC,它的后序遍歷結果為EDBCA,它的順序存儲結構為:

0 1 2 3 4 5 6 7 8
A B C D # # # # E

其實順序存儲結構最后一位結點E,它的左孩子和右孩子都為空,但也是需要申請存儲空間的,但因為他后面無帶數據的根節點,我們可以在代碼上加入一個判斷,當下標超出數組長度時,則均返回null。

進行代碼測試:

1、順序轉鏈式,輸入字符串“ABCD####E”

image-20200406131246227.png

運行結果正確。

2、鏈式轉順序,輸入一串字符”ABD#E###C##“,前序創建樹

image-20200406155130617.png

運行結果正確

全部代碼展示

#include<iostream>
#include<string>
using namespace std;
char BT[100];   //定義全局變量,存儲順序存儲結構的二叉樹
typedef char Elemtype;
typedef string SqBtree;
typedef struct TNode {
	Elemtype data;
	TNode* lchild, * rchild;
}TNode,*BiTree;
/*先序遍歷創建樹*/
int N = 0;
BiTree CreateTree(string s) {
	if (s[N] == '#') {
		N++;
		return NULL;
	}
	BiTree root;
	root = new TNode;
	root->data = s[N];
	N++;
	root->lchild = CreateTree(s);
	root->rchild = CreateTree(s);
	return root;
}
/*順序存儲結構轉鏈式*/
 BiTree Order_to_Chain(SqBtree T, int i,int len) 
{
	 if (i >= len) return NULL;
	BiTree BT;
	if (T[i] == '#')
	{
		return NULL;
	}
	BT = new TNode;
	BT->data = T[i];
	BT->lchild = Order_to_Chain(T, 2 * i+1,len);
	BT->rchild = Order_to_Chain(T, 2 * i + 2,len);
	return BT;
}
/*鏈式存儲結構轉順序*/
void Chain_to_Order(BiTree T,int i)
{
	
	if (T)
	{
		BT[i] = T->data;
		Chain_to_Order(T->lchild, 2 * i + 1);
		Chain_to_Order(T->rchild, 2 * i + 2);
	}
	else
	{
		BT[i] = '#';
	}
}
/*前序遍歷*/
void PreOrder(BiTree b)
{
	if (b != NULL)
	{
		cout << b->data
			<< ' ';
		PreOrder(b->lchild);
		PreOrder(b->rchild);
	}
	else return;
}
/*中序遍歷*/
void InOrder(BiTree b)
{
	if (b != NULL)
	{
		InOrder(b->lchild);
		cout << b->data
			<< ' ';
		InOrder(b->rchild);
	}
	else return;
}
/*后序遍歷*/
void PostOrder(BiTree b)
{
	if (b != NULL)
	{
		PostOrder(b->lchild);
		PostOrder(b->rchild);
		cout << b->data
			<< ' ';
	}
	else return;
}
/*遍歷輸出二叉鏈樹*/
void printTree1(BiTree T)
{
	if (T == NULL) 
		cout << "樹為空";
	else 
	{
		cout << "先序遍歷: ";
		PreOrder(T);
		cout << endl;
		cout << "中序遍歷: ";
		InOrder(T);
		cout << endl;
		cout << "后序遍歷: ";
		PostOrder(T);
		cout << endl;
	}
}
/*輸出順序樹*/
void printTree2(char BT[])
{
	int i;
	cout << "該樹的順序存儲結構為: ";
	for (i = 0; BT[i] != '0'; i++) {
		cout << BT[i];
	}
}
int main() {
	SqBtree s;
	BiTree T;
	{
        /*順序轉鏈序輸入
	  cin >> s;
	  int len = s.size();
	  T = Order_to_Chain(s, 0,len);
	  printTree1(T);
        */
	}
	
	{
        /* 鏈式轉順序
	cin >> s;
	T = CreateTree(s);
	memset(BT, '0', sizeof(BT));  //將BT字符串一鍵初始化為0
	Chain_to_Order(T,0);
	printTree2(BT);
	*/
	}
	return 0;
}


總結

整個代碼設計都是圍繞遞歸來寫的,一開始沒有初始化字符串BT的時候,運行總是出現string subscript out of range的錯誤,這是越界了,然后把string改為一個具有上限的char 【maxsize】的話,就無法確定輸出字符的個數,因此引入了memset一鍵初始化,這樣就既保證了不會越界,也能控制輸出。

代碼中有實現遞歸遍歷輸出,遞歸遍歷分為先序遍歷、中序遍歷和后序遍歷三種。

先序遍歷:訪問根節點;先序遍歷左子樹;先序遍歷右子樹;

中序遍歷:中序遍歷左子樹;訪問根節點;中序遍歷右子樹;(中序序列的根節點的左邊是左子樹的結點,右邊是右子樹的結點)

后序遍歷:后序遍歷左子樹;后序遍歷右子樹;訪問根節點;(后序序列的最后一個結點是根節點)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM