圖說演算法使用JavaScript(二十五)

9-4二元樹節點搜尋

我們先來討論在所建立的二元樹中搜尋單一節點資料。基本上,二元樹在建立的過程中,是依據左子樹<樹根<右子樹的原則建立,因此只須從樹根出發比較鍵值,如果比樹根大就往右,否則由左往下,直到相等就可以找到搜尋的值,如果比到null,無法再前進就代表搜尋不到此值。

二元樹搜尋的演算法

var search=(ptr,val)=> {
     i=1;
     while (true)  {
            if (ptr==null)
                  return null;
             if (ptr.data==val) {
                  process.stdout.write(‘共搜尋 ‘+i+’ 次’+’\n’);
                  return ptr;
              }
              else if (ptr.data>val)
                  ptr=ptr.left;
              else
                  ptr=ptr.right;
              i+=1;
       }
}

JS               binary_search.js

class tree {
	constructor() {
		this.data=0;
		this.left=null;
		this.right=null;
	}
}

var create_tree=(root,val)=> {
	newnode=new tree();
	newnode.data=val;
	newnode.left=null;
	newnode.right=null;
	if (root==null) {
		root=newnode;
		return root;
	}
	else {
		current=root;
		while (current!=null) {
			backup=current;
			if (current.data>val)
				current=current.left;
			else
				current=current.right;
		}
		if (backup.data>val)
			backup.left=newnode;
		else
			backup.right=newnode;
	}
	return root;
}

var search=(ptr,val)=> {
	i=1;
	while (true) {
		if (ptr==null)
			return null;
		if (ptr.data==val) {
			process.stdout.write('共搜尋 '+i+' 次'+'\n');
			return ptr;
		}
		else if (ptr.data>val)
			ptr=ptr.left;
		else
			ptr=ptr.right;
		i+=1;
	}
}

arr=[7,1,4,2,8,13,12,11,15,9,5];
ptr=null;
process.stdout.write('[原始陣列內容]\n');
for (i=0; i<11; i++) {
	ptr=create_tree(ptr,arr[i]);
	process.stdout.write('['+arr[i]+'] ');
}
process.stdout.write('\n');
const prompt=require('prompt-sync')();
const data=parseInt(prompt('請輸入搜尋值:'));
if (search(ptr.data)!=null)
	process.stdout.write('你要找的值 ['+data+'] 有找到!!\n');
else
	process.stdout.write('您要找的值沒找到!!\n');

Java Script的程式有問題!

PHP             binary_search.php

class Node {
    public $data;
    public $left;
    public $right;

    public function __construct($data) {
        $this->data = $data;
        $this->left = null;
        $this->right = null;
    }
}
class BinarySearchTree {
    public $root;

    public function __construct() {
        $this->root = null;
    }

    // 插入節點
    public function insert($data) {
        $this->root = $this->insertNode($this->root, $data);
    }

    private function insertNode($node, $data) {
        if ($node === null) {
            return new Node($data);
        }

        if ($data < $node->data) {
            $node->left = $this->insertNode($node->left, $data);
        } elseif ($data > $node->data) {
            $node->right = $this->insertNode($node->right, $data);
        }

        return $node;
    }

    // 中序走訪(in-order traversal)
    public function inorderTraversal($node = null) {
        if ($node === null) {
            $node = $this->root;
        }

        if ($node !== null) {
            $this->inorderTraversal($node->left);
            echo $node->data . " ";
            $this->inorderTraversal($node->right);
        }
    }

    // 搜尋節點
    public function search($data) {
        return $this->searchNode($this->root, $data);
    }

    private function searchNode($node, $data) {
        if ($node === null) return false;

        if ($data == $node->data) return true;

        if ($data < $node->data) {
            return $this->searchNode($node->left, $data);
        } else {
            return $this->searchNode($node->right, $data);
        }
    }
}
$tree = new BinarySearchTree();

$tree->insert(50);
$tree->insert(30);
$tree->insert(70);
$tree->insert(20);
$tree->insert(40);
$tree->insert(60);
$tree->insert(80);

echo "In-order traversal: ";
//$tree->inorderTraversal(); // Output: 20 30 40 50 60 70 80
echo "\n<br>";

echo "Search 60: " . ($tree->search(60) ? "Found" : "Not Found") . "\n<br>"; // Found
echo "Search 90: " . ($tree->search(90) ? "Found" : "Not Found") . "\n<br>"; // Not Found

此程式是用ChatGPT所產生的,但是它的inorderTraversal()函數有問題。

樹根的功能

細根(0-30公分深)

     主要吸水及吸收養分,顏色是白色的,大小大約05-5公分,但是一旦變成咖啡色就不吸水,生命週期只有兩個星期。
     植物輸送水分、養分要靠呼吸作用提供能量,地表大約1尺深就沒有氧氣,所以細根都長在表層0-30公分。
     頂芽優勢:植物生長會分泌生長激素(Auxin),它讓頂芽生長讓側芽休眠。但是當它到達根部時,濃度變低卻造成細根的發育;但是細根生長時會分泌另一種賀爾蒙,叫做細胞分裂素,它會讓頂芽生長。
    正循環:頂芽生長產生生長激素刺激頂部的細根生長,而細根生長旺盛會產生細胞分裂素,刺激頂芽生長,這樣的循環稱為正循環。反之若是細根長的不好時,就會使頂芽長不好,稱為負循環。


中根

它是由部分的細根肥大後產生的。

粗根

圖說演算法使用JavaScript(二十四)

9-3二元樹走訪的入門捷徑

我們知道線性陣列或串列,都只能單向從頭至尾或反向走訪。所謂二元樹的走訪(Binary Tree Traversal),最簡單的說法就是「拜訪樹中所有的節點各一次」,並且在走訪後,將樹中的資料轉化為線性關係。就以下圖一個簡單的二元樹而言,每個節點都可區分為左右兩個分支。

所以共可以有ABC、ACB、BAC、BCA、CAB、CBA等6種走訪方法。如果是依照二元數特性,一律由左向右,那會只剩下三種走訪方式,分別是BAC、ABC、BCA三種。我們通常把這三種方式的命名與規則如下:

1.中序走訪(BAC,Inorder):左子樹->樹根->右子樹
2.前序走訪(ABC,Preorder):樹根->左子樹->右子樹
3.後序走訪(BCA,Postorder):左子樹->右子樹->樹根

對於這三種走訪方式,各位讀者只需要記得樹根位置就不會前中後序給搞混。例如中序法及樹根在中間,前序法是樹根在前面,後序法則是樹跟在後面。而走訪方式也一定是先左子樹後右子樹。以下針對這三種方式,為各位做更詳盡的介紹。

>>中序走訪

中序走訪(Inorder Traversal)也就是從樹的左側逐步向下方移動,直到無法移動,再追蹤此節點,並向右移動一節點。如果無法再向右移動時,可以返回上一層的父節點,重複左、中、右的步驟進行。如下所示:
1.走訪左子樹。
2.拜訪樹根。
3.走訪右子樹。

中序走訪的遞迴演算法如下:

var inorder=(ptr)=> {
if(ptr!=null) {
inorder(ptr.left);
process.stdout.write('['+ptr.data+']');
inorder(ptr.right);
}
}

>>後序走訪

後續走訪(Postorder Traversal)走訪的順序是先追蹤左子樹,再追蹤右子樹,最後處理根結點,反覆執行此步驟。如下所示:
1.走訪左子樹。
2.走訪右子樹。
3.拜訪樹根。

如下圖的後序走訪為:FHIGDEBCA

後序走訪的遞迴演算法如下:

var postorder=(ptr)=> { //後序走訪
       if (ptr!=null) {
            postorder(ptr.left);
            postorder(ptr.right);
            process.stdout.write(‘[‘+ptr.data+’] ‘);
     }
}

>>前序走訪

前序走訪(Preorder Traversal)是從根節點走訪,再往左右移動,無法繼續時,繼續向右方移動,接著再重複執行此步驟。如下所示:
1.拜訪樹根。
2.走訪左子樹。
3.走訪右子樹。

下圖的前序走訪為:ABDFGHIEC

前序走訪的遞迴演算法如下:

var preorder=(ptr)=> {
       if (ptr!=null) {
            process.stdout.write(‘[‘+ptr.data+’] ‘);
            preorder(ptr.left);
            preorder(ptr.right);
       }
}

JS                 inorder.js

class tree {
	constructor() {
		this.data=0;
		this.left=null;
		this.right=null;
	}
}

var inorder=(ptr)=> {
	if (ptr!=null) {
		inorder(ptr.left);
		process.stdout.write('['+ptr.data+'] ');
		inorder(ptr.right);
	}
}

var create_tree=(root,val)=> {
	newnode=new tree();
	newnode.data=val;
	newnode.left=null;
	newnode.right=null;
	if (root==null) {
		root=newnode;
		return root;
	}
	else {
		current=root;
		while (current!=null) {
			backup=current;
			if (current.data>val)
				current=current.left;
			else
				current=current.right;
		}
		if (backup.data>val)
			backup.left=newnode;
		else
			backup.right=newnode;

	}
	return root;
}

//主程式
data=[5,6,24,8,12,3,17,1,9];
ptr=null;
root=null;
for (i=0; i<9; i++) 
	ptr=create_tree(ptr,data[i]);
process.stdout.write('================\n');
process.stdout.write('排序完成結果:\n');
inorder(ptr);
process.stdout.write('\n');

PHP               inorder.php

                         inorder-gpt.php

目前,還是沒辦法解決二元樹-20250660
吳老師建議查ChatGPT查查看,inorder-中序尋訪可以解,
但是binary_search的inorder有問題。

class TreeNode {
public $val;
public $left;
public $right;
public function __construct($val) {
$this->val = $val;
$this->left = null;
$this->right = null;
}
}
// 中序走訪函式
function inorderTraversal($node) {
if ($node === null) {
return;
}
// 遞迴走訪左子樹
inorderTraversal($node->left);
// 處理當前節點
echo $node->val . " ";
// 遞迴走訪右子樹
inorderTraversal($node->right);
}
// 建立範例二元樹
// 1
// / \
// 2 3
// / \
// 4 5
$root = new TreeNode(1);
$root->left = new TreeNode(2);
$root->right = new TreeNode(3);
$root->left->left = new TreeNode(4);
$root->left->right = new TreeNode(5);
// 執行中序走訪
echo "中序走訪結果: ";
inorderTraversal($root); // 預期輸出:4 2 5 1 3