圖說演算法使用JavaScript(十六)

7-4插入排序法

插入排序法insert sort則是將陣列中的元素,逐一與已排序好的資料作比較,如前兩個元素先排好,再將第三個元素插入適當的位置,所以這三個元素仍然是已排序好,接著再將第四個元素加入,重複此步驟,直到排序完成為止。各位可以看做是在一串有序的紀錄R1、R2..Ri,插入新的紀錄R,使得i+1個紀錄排序妥當。

以下利用55、23、87、62、16數列的由小到大排序過程,來說明插入排序法的演算流程。下圖中,在步驟二,以23為基準與其他元素比較後,放到適當位置(55的前面),步驟三則拿87與其他兩個元素比較後,接著62在比較完前三個數後插入87的前面…,將最後一個元素比較完後即完成排序:

JS          insert.js

let SIZE=8;
	//定義陣列大小
var showdata=(data)=> {
	for (k=0; k<8; k++) {
		process.stdout.write(data[k]+' ');
	}
}

var insert=(data)=> {
	for (i=0; i<SIZE; i++) {
		tmp=data[i];
		//tmp用來暫存資料
		no=i-1;
		while (no>=0 && tmp<data[no]) {
			data[no+1]=data[no];
			//就把所有元素往後推一個位置
			no-=1;
		}
		data[no+1]=tmp;
		//最小的元素放到第一個元素
	}
}
data=[16,25,39,27,12,8,45,63];
console.log('原始陣列是:');
showdata(data);
insert(data);
console.log();
console.log('排序後陣列是:');
showdata(data);

PHP          insert.php

$data=array(16,25,39,27,12,8,45,63);
$count=count($data);

echo "原始陣列:<br>";
showdata($data);

$new_data=insert($data);

echo "<br>排列後的陣列:<br>";
showdata($new_data);

function insert($arr) {
	$count=count($arr);
	//計算陣列大小
	for ($i=0; $i<$count; $i++) {
		$tmp=$arr[$i];
		//用tmp來暫存資料
		$no=$i-1;
		while ($no>=0 && $tmp<$data[$no]){
			$data[$no+1]=$data[$no];
			//就把所有元素往後推一個位置
			$no--;
		}
		$data[$no+1]=$tmp;
		//最小的元素放到第一個元素  
	}
	return $data;
}


function showdata($arr){
	foreach($arr as $key=>$value){
		echo $value."、";
	}
	echo "<br>";
}

7-5謝耳排序法

我們知道如果原始紀錄的鍵值大部分以排序好的情形下,插入排序法或非常有效率,因為它無須做太多的資料搬移動作。[謝耳排序法]是D.L.Shell在1959年7月所發明的一種排序法,可以減少插入排序法中資料搬移的次數,以加速排序進行。排序的原理是將資料分成特定間隔的幾個小區塊,以插入排序法排完區塊內的資料後再漸漸減少間隔的距離。

以下利用63、92、27、36、45、71、58、7數列的由小到大排序過程,來說明謝耳排序法的演算過程。

範例:shell.js>請設計一程式,並使用謝耳排序法來將以下的數列排序:
16,25,39,27,12,8,45,63

JS           shell.js

let SIZE=8;

var showdata=(data)=> {
	for (i=0; i<SIZE; i++) {
		process.stdout.write(data[i]+ ' ');
	}
	console.log();
}

var shell=(data, size)=> {
	k=1;
	//k列印計數
	jmp=parseInt(size/2);
	while (jmp !=0) {
		for (i=jmp; i<size-1; i++) {
			//i為掃描次數 jmp為設定間距位移量
			tmp=data[i];
			//tmp用來暫存資料
			j=i-jmp;
			//以j來定位比較的元素
			while (tmp<data[j] && j>=0) {
				//插入排序法
				data[j+jmp] = data[j];
				j=j-jmp;
			}
			data[jmp+j]=tmp;
		}
		process.stdout.write('第 '+k+' 次排序過程:');
		k=k+1;
		showdata(data);
		console.log('------------------------------------');
		jmp=parseInt(jmp/2);
		//控制迴圈數
	}
}

data=[16,25,39,27,12,8,45,63];
process.stdout.write('原始陣列是:     ');
showdata(data);
console.log('-------------------------------------');
shell(data, SIZE);

PHP            shell.php

$data=array(16,25,39,27,12,8,45,63);
echo "原始陣列:<br>";
print_arr($data);
echo "----------------------------<br><br>";


$size=count($data);
$new_data=shell_sort($data, $size);

echo "<br>排序後的陣列:<br>";
print_arr($new_data);

function shell_sort($arr, $size) {
	$k=1;
	//k列印計數
	$jmp=intval($size/2);
	
	while($jmp!=0) {
		for($i=$jmp; $i<$size-1; $i++) {
			//i為掃描次數 jmp為設定間距位移量
			$tmp=$arr[$i];
			//tmp用來暫存資料
			$j=$i-$jmp;
			//以j來定位比較的元素
			while ($tmp<$arr[$j] && $j>=0) {
				//插入比較法
				$arr[$j+$jmp]=$arr[$j];
				$j=$j-$jmp;
				isset($arr[$j])?$arr[$j]=$arr[$j]:$arr[$j]=null;
				//偵測$arr[$j]的key值是否為正確
				//echo $j."<br>";
			}
			$arr[$jmp+$j]=$tmp;
		}
		echo "第".$k."次排序過程<br>";
		$k++;
		print_arr($arr);
		$jmp=intval($jmp/2);
		//控制迴圈數
	}
	
	return $arr;	
}

function print_arr($arr) {
	foreach ($arr as $key => $value){
		echo $value." ";
	}
	echo "<br>";
}

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

7-2氣泡排序法

氣泡排序法又稱為交換排序法,是由觀察水中氣泡變化構思而成,原理是由第一個元素開始,比較相鄰元素大小,如果大小順序有誤,則對調後在進行下一個元素的比較,就彷彿氣泡逐漸由水底逐漸升到水面上一樣。如此掃描過一次之後就可確保最後一個元素是位於正確的順序。接著再逐步進行第二次掃描,直到完成所有元素的排序關係為止。

以下排序我們利用55、23、87、62、16的排序過程,您可以清楚知道氣泡排序法的演算流程:

由此可知5個元素的氣泡排序法必須執行5-1次掃描,第一次掃描需比較5-1次,共比較4+3+2+1=10次。

JS               bubble.js

var data=[16, 25, 39, 27, 8 ,45, 63];   
//原始資料
console.log('氣泡排序法:原始資料為:');
for (i=0; i<8; i++) 
	process.stdout.write(data[i]+' ');

console.log();

for (i=7; i>0; i--) {    //掃描次數
	for (j=0; j<i; j++) {
		if(data[j]>data[j+1])  {     
		//比較,交換的次數
			temp=data[j];
			data[j]=data[j+1];      
			//比較相鄰兩數,如果第一數較大則交換
			data[j+1]=temp;
		}
	}
	process.stdout.write('第 ' +(8-i)+ ' 次排序後的結果是:')    
	//把各次結果掃描出來
	for (j=0; j<8; j++) process.stdout.write(data[j]+' ');
		console.log();
}
console.log('排序後結果為:');
for (j=0; j<8; j++) process.stdout.write(data[j]+ ' ');
console.log(); 

PHP          buble.php

$data = array("16","25","39","27","8","45","63");
//原始資料
echo "原本陣列是:";
arr_print($data);
echo "<br><br>";

$count=count($data);
for ($i=$count-1; $i>0; $i--){
	//掃描次數
	for ($j=0; $j<$i; $j++){
		//比較,交換的次數
		if ($data[$j]>$data[$j+1]){
			$temp=$data[$j];
			$data[$j]=$data[$j+1];
			//比較相鄰兩數,如果第一數較大則交換
			$data[$j+1]=$temp;
		}

	}
	$time=7-$i;
	echo "第{$time}次";
	arr_print($data);
	echo "<br>";
}
echo "<br><br>";
echo "排完陣列是:";
arr_print($data);

function arr_print($arr){
	foreach ($arr as $key => $value) {
		echo $value." ";
	  	echo "--";
	}
}

7-3選擇排序法

選擇排序法Selection Sort也算是枚舉法的應用,概念就是反覆從未排序的數列中取出最小的元素,加入到另一個數列,結果即為已排序的數列。選擇排序法可使用兩種方式排序,一圍在所有的資料中,當由大至小排序時,則將最大值放入第一位置;若由小至大排序時,則將最大值放入為至末端。例如一開始在所有的資料中挑選一個最小項放在第一個位置(假設是由小到大),再從第二筆開始挑選一個最小項放在第2個位置,依樣重複,直到完成排序為止。

以下利用55、23、87、62、16數列的由小到大排序過程,來說明選擇排序法的演算過程:

JS          select.js

var showdata=(data)=>   {
	for (k=0; k<8; k++){
		process.stdout.write(data[k]+' ');
	}
}

var select=(data)=> {
	for(i=0; i<7; i++) {
		smallest=data[i];
		index=i;
		for (j=i+1; j<8; j++) {
			//由i+1比較起
			if (smallest>data[j]) {
			//找出最小元素
			smallest=data[j];
			index=j;	
			}	
		}
	tmp=data[i];
	data[i]=data[index];
	data[index]=tmp;
	console.log();
	process.stdout.write('第'+(i+1)+"次排序結果: ");
	showdata(data);
	}
}

data=[63,25,39,27,12,8,45,16];
process.stdout.write('原始資料為:');
for (i=0; i<8; i++) process.stdout.write(data[i]+' ');
	console.log();
	console.log("----------------------------");
	select(data);
	console.log();
	console.log("----------------------------");
	process.stdout.write("排序後資料");
for (i=0; i<8; i++) process.stdout.write(data[i]+'  ');
	console.log();
	console.log("----------------------------"); 

PHP          select.php

$data = array("16","25","39","27","8","45","63");
//原始資料
echo "原本陣列是:";
arr_print($data);
echo "<br><br>";

$count=count($data);

for ($i=0; $i<$count-1; $i++) {
	$smallest=$data[$i];
	$index=$i;
		for ($j=$i+1; $j<$count; $j++) {
					//由i+1比較起
			if($smallest>$data[$j]){
					//找出最小元素
				$smallest=$data[$j];
				$index=$j;
			}
		}
	$tmp=$data[$i];
	$data[$i]=$data[$index];
	//兩個交換
	$data[$index]=$tmp;
	//把$tmp換回來
	$num=$i+1;
	echo "第{$num}次排序結果:";
	arr_print($data);
	echo "<br>";
	
}

echo "<br><br>";
echo "排完陣列是:";
arr_print($data);

function arr_print($arr){
	foreach ($arr as $key => $value) {
		echo $value." ";
	  	echo "--";
	}
}

114年民俗體育週

這一週有著滿滿的行程,先是週二到週三的Super Star 民俗體育競賽,是由後後壁國小主辦。主要項目是:國術彈腿、扯鈴、跳鼓、跳繩。
接下來兩天是跳繩比賽:跳繩接力賽、跳繩錦標賽,由柳營國小跟新泰國小主辦。跳繩接力賽成績輸入有學生志工幫忙,只是列印成績的影印機速度太慢;反倒是最後一天的跳繩錦標賽,項目多,成績多,印獎狀的份數多,加上主辦新泰國小是第一次辦,很多不清楚(不知道是不是事先沒想好),導致流程很不順暢,有許多需要改善的。