非遞歸學習樹結構(三)--深廣優先搜



深度優先搜索和廣度優先搜索是樹形結構中常用的兩種搜索遍歷方式,其實更多的是用在圖中的,深度優先搜索可以用來判斷有向圖中是否存在環,廣度優先搜索就更有用了,常用的路徑搜索算法一般都是建立在廣度優先搜索的基礎上,如dijkstra(迪傑斯特拉)算法,A*算法等,感覺兩者的唯一區別就是A*算法中在計算路徑權重時加入了一個估價函數,來改變廣搜的方向,讓搜索向目的地方伸展,減少無用搜索的數量,所以A*算法做的好不好,完全是由其估價函數決定的(只是個人感覺)。

言歸正傳,這裏暫且先不討論圖的遍歷,後續有機會再分析,我們現在先來看一下相對簡單的樹的深搜和廣搜(層次遍歷),

深搜就是:一根筋到底式搜索,

廣搜就是:從頭層層推進的搜索

直接上代碼進行分析,前面的文章已經介紹了建樹的過程,我們這裏就不對建樹過程在多做解釋,直接看深搜和廣搜的代碼


/*BST.c*/
/*深度優先遍歷使用了棧結構,廣度優先遍歷使用了隊列結構*/
/*深度優先遍歷*/
/**/
void DFS(Node* root)
{
	Stack stack;
	registstack(&stack);
	stack.init_size(&stack, 1000);
	/*判斷是否是空樹*/
	if (NULL == root)
	{
		printf(" empty tree!!!\n ");
		return;
	}

	/*保存根節點到棧中*/
	Node* tmp = root;
	stack.push(&stack, tmp);
	/*棧爲空時推出循環*/
	while (!stack.is_empty(&stack))
	{
		tmp = stack.top(&stack);
		stack.pop(&stack);
		printf("%d\t",tmp->val);

		/*這裏爲什麼要先將右子樹入棧呢?因爲先入棧的後出棧
		                   A
				      /    \
				     B      C
				    /  \    / \
				   D    E  F   G
	    以上面的樹爲例,A在循環開始之前就已經入棧,
		第一次循環:進入循環時,A出棧,輸出A的值,然後將C(右子節點)入棧,
		           再將B(左子節點)入棧,
		第二次循環:將B先出棧(後入先出)然後將B的右子節點E入棧,左子節點D入棧,
		           已經輸出值的結點是AB,此時棧內元素依次爲CED,
		第三次循環:棧內元素是ED,D是後進入,因此先輸出D,D沒有子節點,
		           因此本次循環沒有新元素入棧,棧內元素爲CE
		第四次循環:E出棧,E也沒有子節點,因此本次循環也沒有元素入棧,
		           棧內元素爲C
		第五次循環:C出棧,將G和F入棧,棧內元素爲GF
		第六次循環:將F出棧,F無子節點,因此此次循環沒有元素入棧,
		           棧內元素爲G
		第七次循環:將G出棧,因爲G沒有子節點,因此本次循環沒有元素入棧,
		           此時棧爲空,因此循環結束
		*/
		if (tmp->prc)
			stack.push( &stack, tmp->prc  );
		if (tmp->plc)
			stack.push( &stack, tmp->plc  );
	}
}

/*廣度優先搜索*/
void BFS(Node* root)
{
	Node* tmp = root;

	if (tmp == NULL)
	{
		printf("Tree is empty!!!");
		return;
	}

	Queue queue;/*申請個隊列變量	*/
	registerqueue(&queue);
	queue.initqueue(&queue);

	queue.push(&queue, tmp);/*將根節點先入隊*/
	/*隊列爲空時退出循環*/
	while (!queue.is_empty(&queue))
	{
		/*輸出隊頭元素值*/
		tmp = queue.get(&queue)->val;
		printf("%d\t",tmp->val);
		/*隊列的特點是先進先出,因此我們以下例進行分析樹的廣度優先遍歷過程
		      A
		    /    \
		   B      C
		  /  \   /  \
		 D    E  F   G
		 第一次循環:進入循環時,隊列裏只有A節點,輸出A節點的值,然後將B節點入隊,
		            再將C節點入隊,然後將A節點出隊
		 第二次循環:進入循環時,隊列內有BC兩個元素,因爲B是先進入的,先進先出的原則下本次循環輸出B,
		            然後將D和E依次入隊,B元素出隊,隊列元素爲CDE
		 第三次循環:進入循環時,隊列內有CDE,隊頭元素是C,因此輸出C,再將C的左右子節點FG入隊,
		            將C出隊,此時隊內原始依次是DEFG
		 第四次循環:進入循環時,隊內元素是DEFG,先將D輸出,因爲D沒有子節點,因此本次循環沒有元素入隊,
		            D出隊,隊內元素爲EFG
		 第五次循環:E輸出,沒有元素入隊,E出隊,
		 第六次循環:F輸出,沒有元素入隊,F出隊,
		 第七次循環:G輸出,沒有元素入隊,G出隊,隊列爲空,退出循環
		*/
		if (tmp->plc != NULL)
		{
			queue.push(&queue, tmp->plc);
		}
		if (tmp->prc != NULL)
		{
			queue.push(&queue,tmp->prc);
		}
		queue.pop(&queue);
	}
}

以上就是深度優先和廣度優先搜索的具體代碼,代碼僅供簡述原理使用,錯誤之處,請指正。


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