c語言實現順序二叉樹的非遞歸的三種遍歷算法

二叉樹的概念遍地都是,就不詳說了。不管是順序的還是鏈式的二叉樹,實現的方法基本上都是遞歸的例子,我就自己看着遍歷的方法,寫出了這一個程序,程序中每個遍歷實現思想都有詳細描述,代碼略顯繁瑣,歡迎讀者批評指正。使用的例子看附圖,也算是自己的一個學習筆記。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>

#define Max_Size 100
#define null '#'//表示爲空

//可以當做一個數據類型
typedef char BinaryTree[Max_Size];

//初始化二叉樹中每個節點爲空
void InitTree(BinaryTree tree)
{
	int i;
	for(i=0;i<Max_Size-1;i++)
	{
		tree[i] = null;
	}
	tree[i] = '\0';
}

void CreateTree(BinaryTree tree,char *strtree)
{
	int len = strlen(strtree);

	if(strtree[0] == null)
	{
		printf("樹根節點不能爲空");
		return ;
	}
	int i;
	for(i=0;i<len;i++)
	{
		tree[i] = strtree[i];

		//樹節點從0開始,若從1開始,則判斷條件改爲:tree[(i+1)/2]
		if((tree[(i+1)/2 - 1] == null) &&(tree[i] != null))
		{
			printf("構造二叉樹錯誤,子節點沒有父節點.\n節點爲%d  %c.\n",i+1,tree[i]);
			exit(1);
			return;
		}
	}
}

//使用完全二叉樹求深度的公式[log₂N]+1   [x]取不大於x的整數
int Length(char *strtree)
{
	printf("二叉樹字符串:%s\n完全二叉樹的節點數::%d\n",strtree,strlen(strtree));
	//c語言提供的函數log10
	float a = log10((double)strlen(strtree)),b = log10(2.0);
	//計算深度函數
	int len = a/b + 1;
	printf("二叉樹深度爲:%d\n",len);

	return len;
}

int Is_Empty(BinaryTree tree)
{
	if(tree[0] == '#' || tree[0] == '\0')
	{
		printf("二叉樹爲空!\n");
		return 1;
	}

	return 0;
}

//有效節點個數
int Count(BinaryTree tree)
{
	int count=0;
	int len = strlen(tree);
	int i=0;
	while(i < len)
	{
		if(tree[i] != '#')
		{
			count++;
		}
		i++;
	}

	return count;
}

//先序遍歷實現思想:(根據輸出的有效節點個數來作爲循環的終止條件)
//一:從根節點出發,先打印根節點,
//二:尋找下一個左節點,
//三:若節點不爲空,打印該節點並重復步驟二
//四:若節點爲空,判斷該節點的兄弟右節點
//五:	若不爲空,從該節點開始,重複步驟二
//六:	若爲空,回退至上一個節點,重複步驟四
//注:(回退時注意從左節點開始回退,避免兩個不同子樹的右孩子與左孩子有聯繫)
void PreOrderTraverse(BinaryTree tree)
{
	char Strtree[Max_Size];
	strcpy(Strtree,tree);

	if((Is_Empty(Strtree) == 1))
	{
		return;
	}

	int len = Count(Strtree);
	int k=0,i=0;//i表示節點在完全二叉樹中的位置

	//根據輸出的有效節點個數來作爲循環的終止條件
	while(k < len)
	{
		while(Strtree[i] != '#')
		{
			//打印有效節點
			printf("%c ",Strtree[i]);
			Strtree[i] = '#';//標誌節點已被打印爲空
			k++;
			//繼續尋找左節點
			i = (i+1)*2 - 1;
			if(Strtree[i] == '#')
			{
				break;
			}
		}

		//遍歷右節點
		if(Strtree[i+1] != '#')
		{
			i = i + 1;
		}
		else
		{
			//回退過程
			i = (i+1)/2 - 1;

			if(i%2 == 0 )
			{
				 i = i - 1;
			}
		}

	}
}


//中序遍歷實現思想:(根據輸出的有效節點個數來作爲循環的終止條件)
//一:對於任意一個節點,先找到它的最左節點,最左節點的下一個左節點一定是空的
//二:回退至上一個節點,判斷該節點是否爲空(左子樹打印過程中會置空,回退時避免打印無效節點):
//三:	若不爲空,打印該節點,繼續判斷該節點的右孩子,若不爲空,重複步驟一;
//四:	若爲空,重複步驟二。
void MidOrderTraverse(BinaryTree tree)
{
	char Strtree[Max_Size];
	strcpy(Strtree,tree);

	if((Is_Empty(Strtree) == 1))
	{
		return;
	}

	int len = Count(Strtree);
	int i=0,k=0;//i表示節點在完全二叉樹中的位置

	while(k<len)
	{
		//新一個右節點就尋找該子樹的最左節點
		while((Strtree[i] != '#'))
		{
			i = 2*(i+1)-1;
		}

		//回退至父節點
		i = (i+1)/2 - 1;
		if(Strtree[i] != '#')
		{
			printf("%c ",Strtree[i]);
			Strtree[i] = '#';//標誌節點已被打印爲空
			k++;
		}

		if(Strtree[(i+1)*2] != '#')
		{
			i= (i+1)*2;
		}
	}
}

//後序遍歷實現思想:
//一:對於任意一個節點,先找到它的最左節點,最左節點的下一個左節點一定是空的,判斷該兄弟(右)節點:
//二:若爲空,回退至父節點,打印並輸出該節點,判斷該節點的兄弟(右)節點
//三:	若不爲空,重複步驟一
//四:	若爲空,重複步驟二
//注:判斷右節點是否爲空之前,先要判斷該節點是否爲右節點,如果是就要跳過該判斷。
//數組的方式存儲完全二叉樹,除開根節點,右節點所在位置都是偶數,故用:i%2判斷
void PostOrderTraverse(BinaryTree tree)
{
	char Strtree[Max_Size];
	strcpy(Strtree,tree);

	if((Is_Empty(Strtree) == 1))
	{
		return;
	}

	int len = Count(Strtree);
	int i=0,k=0;//i表示節點在完全二叉樹中的位置

	while(k<len)
	{
		//新一個右節點就尋找該子樹的最左節點
		while((Strtree[i] != '#'))
		{
			i = 2*(i+1)-1;
		}

		//如果最左節點的兄弟(右)節點不爲空,繼續下一輪循環
		if(Strtree[i+1] != '#' && (i%2 !=0) )
		{
			i = i + 1;
			continue;
		}

		//回退至父節點
		i = (i+1)/2 - 1;
		if(Strtree[i] != '#')
		{
			//printf("i = %d\n",i);
			printf("%c ",Strtree[i]);
			Strtree[i] = '#';//標誌節點已被打印爲空
			k++;
		}

		//判斷兄弟(右)節點(在完全二叉樹中,右節點一定爲偶數(除開根節點))
		if(Strtree[i+1] != '#')
		{
			if(i%2 != 0)
			{
				i= i+1;
			}
		}
	}

}

int main()
{
	BinaryTree tree;

	char BinaryTree[Max_Size] = "-+/a*ef##b-##########cd";//第一個圖
	//char BinaryTree[Max_Size] = "fdgbe#iac####hj";//第二個圖
	//char BinaryTree[Max_Size] = "AB#CD####EF#########G";

	InitTree(tree);

	CreateTree(tree,BinaryTree);

	Length(BinaryTree);

	printf("有效節點個數:%d\n",Count(tree));

	printf("先序遍歷如下:\n");
	PreOrderTraverse(tree);

	printf("\n中序遍歷如下:\n");
	MidOrderTraverse(tree);

	printf("\n後序遍歷如下:\n");
	PostOrderTraverse(tree);

	return 0;
}

運行結果示例:




發佈了26 篇原創文章 · 獲贊 12 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章