1. 程式人生 > >資料結構——樹與二叉樹的性質,二叉樹的建立,遍歷,插入,列印,查詢左右兄弟等

資料結構——樹與二叉樹的性質,二叉樹的建立,遍歷,插入,列印,查詢左右兄弟等

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

#define MAX(x,y) (x) >= (y)?(x):(y)
/*
結點的層次:從根到該結點的層數(根節點算第一層)

終端結點:度為0的結點,即葉子

分支結點:除樹根結點以外的結點,也稱內部結點

樹的度:所有結點中的最大值 MAX{各結點的度}

樹的深度:所有結點中的最大層數 Max{各結點的層次}

樹的表示方法:1.圖形表示法 
             2.廣義表表示方法 
             3.左孩子-右兄弟表示法

陣列的儲存方式:1.順序儲存:從上到下,從左到右的儲存方式,缺點:複雜困難,復原困難
               2.鏈式儲存
將樹轉換為簡單的樹表示,進行操作

二叉樹的性質:
1.有序樹,左右子樹的順序不能互換
2.每個節點只能有兩個子樹
3.二叉樹每層上至多有2^(i-1)個結點,
4.深度為K的二叉樹,至多有2^k-1個結點,
5.二叉樹,2度的結點樹有n2個。則葉子樹n0必定為n2+1

滿二叉樹:深度為K且有2^(k-1)個結點的二叉樹
完全二叉樹:深度為k有n個結點的二叉樹,當且僅當每一個結點都與深度為k的滿二叉樹中編號從1到n的結點一一對應,只有最後一層葉子不滿,且都集中在左邊。

線索二叉樹的性質:
1.若結點有左子樹,則lchild指向左孩子;否則,lchild指向其直接前驅(即線索)
2.結點有右子樹,rchild指向右孩子,否則,rchild指向其直接後繼(即線索)

通過標誌位判定:Ltag Rtag 為0時,表示正常情況,為1時表示線索情況
*/
struct tree
{
	int nodedata=0;
	tree *LC=nullptr, *RC=nullptr;
};
tree Btree, *pBtree;
/*
       1
	2      3
  4   5  6
 
 層序,中序,前序,後序遍歷二叉樹
 */
//遞迴方式列印二叉樹
void show(tree *proot,int n)
{
	if (proot== nullptr )
	{
		return;
	}
	else 
	{
		show(proot->RC,n+2);//遞迴執行到右子樹的最後一個結點,沒有左右子樹為止
		for (int i = 0;i < n;i++)
		{
			cout << ' ';
		}
		cout << proot->nodedata << endl;//列印結點資料
		show(proot->LC, n + 2);//遍歷左子樹	
	}
}
//插入二叉樹
tree *insertnode(tree *proot, int num)
{
	if (proot == nullptr)
	{
		tree *pnew = new tree;
		pnew->nodedata = num;
		proot = pnew;
	}
	else if(num<=proot->nodedata)
	{
		proot->LC = insertnode(proot->LC, num);
	}
	else
	{
		proot->RC = insertnode(proot->RC, num);
	}
	return proot;
}
//遞迴方式遍歷二叉樹
//中序遍歷二叉樹
void LDR(tree *proot)
{
	if (proot == nullptr)
	{
		return;
	}
	LDR(proot->LC);
	cout << " " << proot->nodedata << endl;
	LDR(proot->RC);	
}
//後序遍歷
void LRD(tree *proot)
{
	if (proot == nullptr)
	{
		return;
	}
    LRD(proot->LC);
    LRD(proot->RC);
    cout << " " << proot->nodedata << endl;
}
//前序遍歷
void DLR(tree *proot)
{
	if (proot == nullptr)
	{
		return;
	}
	cout << " " << proot->nodedata << endl;
	DLR(proot->LC);
	DLR(proot->RC);
}
//二叉樹的層序遍歷
void cengbianli(tree *proot)
{
	if (proot == nullptr)
	{
		return;
	}
	tree * myq[100];
	int tou = 0;
	int wei = 0;
	tree *pcurr = nullptr;
	myq[wei++] = proot;//存入佇列第一個結點,入隊
	while (tou != wei)
	{
		pcurr = myq[tou];//取出第一個元素,
		tou++;//出隊,指向第二個元素的位置
		cout << pcurr->nodedata << endl;
		if (pcurr->LC)//第二個元素入隊,然後指向下一個位置
		{
			myq[wei++] = pcurr->LC;
		}
		if (pcurr->RC)
		{
			myq[wei++] = pcurr->RC;
		}


	}

}
//非遞迴方式遍歷二叉樹
void shuzhuLDR(tree *proot)
{
	tree * pcurr = proot;
	tree * mytree[20];
	int top=0;
	while (top != 0 || pcurr != nullptr)
	{
		while (pcurr != nullptr)
		{
			mytree[top++] = pcurr;
			pcurr = pcurr->LC;
		}
		if (top > 0)
		{
			top--;
			pcurr = mytree[top];
			cout << " " << pcurr->nodedata << endl;
			pcurr = pcurr->RC;
		}
	}
}
//棧中序遍歷
void stackLDR(tree *proot)
{
	tree * pcurr = proot;
	stack<tree *> mytree;
	while (!mytree.empty()|| pcurr != nullptr)
	{
		while (pcurr != nullptr)
		{
			mytree.push(pcurr);
			pcurr = pcurr->LC;
		}
	     if(!mytree.empty())
		 {
			pcurr = mytree.top();
			cout<< " " << mytree.top()->nodedata<< endl;
		    mytree.pop();
			pcurr = pcurr->RC;
		}
	}
}
//列印二叉樹的葉子結點個數
int getyezi(tree *proot)
{
	int left = 0, right = 0;
	if (proot == nullptr)
	{
		return 0;
	}
	if(proot->LC==nullptr&&proot->RC==nullptr)
	{
		return 1;
	}
	left = getyezi(proot->LC);
    right = getyezi(proot->RC);

	return left + right;
}
//列印二叉樹的深度
int getheight(tree *proot)
{
	
	int heightleft = 0,heightright=0;
	if (proot == nullptr)
	{
		return 0;
	}
	heightleft =getheight(proot->LC);
	heightright=getheight(proot->RC);

	return (heightleft >=heightright? heightleft : heightright)+1;
}

//獲得指定元素的父結點
int getroot(tree *proot, int num)
{
	if (proot == nullptr)
	{
		return 0;
	}
	if (proot->LC != nullptr&&proot->LC->nodedata == num)
	{
		return proot->nodedata;
	}
	if (proot->RC != nullptr&&proot->RC->nodedata == num)
	{
		return proot->nodedata;
	}

	getroot(proot->LC,num);
	getroot(proot->RC,num);

}
//獲得左兄弟的值
int getleft(tree *proot, int num)
{
	if (proot == nullptr)
	{
		return 0;
	}
	if (proot->RC && proot->RC->nodedata == num)
	{
		if (proot->LC)
		{
			return proot->LC->nodedata;
		}
	}

	return getleft(proot->LC, num)>=getleft(proot->RC, num)? getleft(proot->LC, num):getleft(proot->RC, num);
}
//獲得右兄弟的值
int getright(tree *proot, int num)
{
	if (proot == nullptr)
	{
		return 0;
	}
	if (proot->LC &&proot->LC->nodedata == num)
	{
		if (proot->RC)
		{
			return proot->RC->nodedata;
		}
	}
	return getright(proot->LC,num) >= getleft(proot->RC, num) ? getright(proot->LC, num):getleft(proot->RC,num);//返回查詢結果
}
//找到二叉樹中最大的元素
int findmax(tree *proot)
{
	int max = -9999;
	tree * pcurr = proot;
	stack<tree *> mytree;
	while (!mytree.empty() || pcurr != nullptr)
	{
		while (pcurr != nullptr)//1 2 4 入棧
		{
			mytree.push(pcurr);
			pcurr = pcurr->LC;
		}
		if (!mytree.empty())
		{
			pcurr = mytree.top();
			//cout << " " << mytree.top()->nodedata << endl;
			if (max < pcurr->nodedata)
			{
				max = pcurr->nodedata;
			}
			mytree.pop();
			pcurr = pcurr->RC;
		}
	}
	return max;
}
void main1()
{
	tree *proot;//根結點
	tree s1, s2, s3, s4, s5, s6;
	s1.nodedata = 1;
	s1.LC = &s2;
	s1.RC = &s3;
	
	s2.nodedata = 2;
	s2.LC = &s4;
	s2.RC = &s5;

	s3.nodedata = 3;
	s3.LC = &s6;
	s3.RC = nullptr;

	s4.nodedata = 4;
	s5.nodedata = 5;
	s6.nodedata = 6;
	proot = &s1;

	insertnode(proot,7);
	show(proot,2);

	cout << "中序遍歷" << endl;
	LDR(proot);

	cout << "前序遍歷" << endl;
	DLR(proot);

	cout << "後序遍歷" << endl;
	LRD(proot);

	cout << "中序遍歷" << endl;
	cout << endl;
	shuzhuLDR(proot);

	cout << "中序遍歷" << endl;
	cout << endl;
	stackLDR(proot);

	cout << "葉子結點個數" << endl;
    cout << getyezi(proot) << endl;

	cout << "樹的深度" << endl;
	cout << getheight(proot) << endl;

	cout << "層序遍歷" << endl;
	cengbianli(proot);
	
	cout << "獲得指定元素的父結點"<<endl;
	cout << getroot(proot, 6) << endl;

	cout << "獲得左兄弟的值" << endl;
	cout << getleft(proot,5) << endl;

	cout << "獲得右兄弟的值" << endl;
	cout << getright(proot,4) << endl;

	cout << "findmax" << endl;
	cout<<findmax(proot) << endl;
	
	cin.get();
}

void main2()
{
	tree *proot;
	tree sarry[100];
	proot = sarry;
	for (int i=1;i <= 100;i++)
	{
		sarry[i-1].nodedata = i;
	}

	for (int i = 0;i <= 50;i++)
	{ 
		if (i <= (99 - 1) / 2)
		{
			sarry[i].LC = &sarry[2 * i + 1];
		}
		if (i <= (99 - 2) / 2)
		{
			sarry[i].RC = &sarry[2 * i + 2];
		}
	}
	show(proot, 2);
	cin.get();
}
void main()
{
	tree *proot=nullptr;
	for (int i = 5;i < 10;i++)
	{
		proot = insertnode(proot,i);
	}
	for (int i = 4;i >0;i--)
	{
		proot = insertnode(proot, i);
	}

	show(proot,2);


	cin.get();
}