1. 程式人生 > >資料結構與演算法之二 排序

資料結構與演算法之二 排序

   視訊解析  https://edu.csdn.net/course/play/7813 假定,你要為你的生日聚會邀請你的朋友和親戚。對此,你需要給他們打電話。你正在擁有10,000條記錄的電話本中查詢名為Steve的電話號碼。然而,電話本中的記錄是以隨意順序儲存的。要在這樣一個目錄中查詢你朋友的電話號碼,你需要按順序在目錄中瀏覽每個條目。這將非常耗時,你如何解決此問題呢?

    

節省時間和高效搜尋資料的簡單解決方案是排序。 排序 是按照某些預定義的順序或序列排列資料的過程。 此順序可以是升序
或降序。 如果資料被排序,則可以直接轉到儲存以 S 開頭的姓名部分,因此減少了要 遍歷的記錄數。


選擇排序演算法

通過使用一演算法實現在程式中排序。 一些排序演算法有: 冒泡 Bubble 排序 選擇排序 插入排序 殼( Shell )排序 合併排序 快速排序 堆排序 要選擇合適的演算法,你需要考慮以下方面:
執行時間 儲存空間 程式設計工作


氣泡排序演算法: 是最簡單的排序演算法之一 此演算法具有二次方程增長階,因此適合僅排序小列表 通過列表重複掃描、比較相鄰元素和按錯誤順序交換,此演算法會有作用 .


編寫一演算法以實現 泡排序。 泡排序的演算法是: 1. 設定通道 ( 圈數 ) = 1 2.
重複步驟 3   區分 0 n 1 通道中的 j 1. 如果索引 j 處的元素大於索引 j + 1 處的元素,則交換這兩個元素。 3. 1 遞增通道 ; 圈數加 1 4. 如果通道 <= n-1 ,則轉到第 2


排序演算法的效率按照比較次數來測量。 泡排序中,通道 1 內有 n 1 次比較,通道 2 中有 n 2 次比較,依此類推。 比較總數 = (n – 1) + (n – 2) + (n – 3) + … + 3 + 2 + 1 = n(n 1)/2 n(n 1)/2 O(n2) 階的級數。 因此, 泡排序演算法是階 O(n2) 的演算法。


什麼是氣泡排序演算法的增長階? 答案: n 1 次比較

答案: 氣泡排序演算法具有二次方增長階

當實現氣泡排序演算法時,在通道1中將執行多少次比較? 答案: n 1次比較
使用選擇排序來排序資料
選擇排序演算法: 選擇排序還具有二次方程增長階,且因此僅適用於排序小的列表。 選擇排序通過列表反覆掃描,每次掃描選擇一項,然後將這一項移動到列表中 正確的位置。

要理解選擇排序演算法的實現,考慮陣列中儲存的未排序的數字列表。每次都尋找最小值,將最小值往前放

編寫一演算法以實現選擇排序。 選擇排序的演算法: 1. 重複步驟 2 3 區分 0 n -2 通道中的 j 2. 找出 arr[j] arr[n 1] 中的最小值 a. 設定 min_index = j b. 重複步驟 c 區分 j + 1 n 1 i c. 如果 arr[i] < arr[min_index]:   i.    min_index = i 3. arr[j] arr[min_index] 交換

在選擇排序中, 在查詢最小元素的通道 1 中有 n 1 次比較。 在查詢第二個最 小元素的通道 2 中有 n -2 次比較,依此類推。 比較總數 = (n – 1) + (n – 2) + (n – 3) + … + 3 + 2 + 1 = n(n 1)/2 n(n 1)/2 O(n2) 階的級數。 因此,選擇排序演算法是階 O(n2) 的演算法。

插入排序演算法: 具有二次方程增長階,且因此僅用於排序小列表。 如果需要排序的列表幾乎已經排序,則插入排序比氣泡排序和選擇排序更有效率。

要理解插入排序演算法的實現,考慮陣列中儲存的未排序的數字列表。


要使用插入排序演算法排序此列表: 你需要將列表分為兩個子列表,即排序和未排序。

若要通過使用插入排序排序大小為n的列表,您需要執行(n 1) 次通道。 最佳用例效率: 當列表已經被排序時產生最佳用例。 在這種情況下,您必須在每個通道中僅做一次比較。 n 1次通道中,您將需要做n 1次比較。 插入排序的最佳用例效率是O(n)階的。 最糟用例效率 當列表按反向順序排序時產生最糟用例效率。 在這種情況下,您需要在第1個通道中做1次比較,在第二個通道中做2次比較,在第3個通道中做3次比較,在第n 1 個通道中做n 1次比較。 插入排序的最糟用例效率是O(n2)階的。


銷售經理對2004-2006念市場上最佳冷飲銷售員進行調查。David是一名軟件開發人員,他有一個冷飲品牌及其銷售資料的檔案。 David 必須向銷售經理提供排序好的資料。檔案總的資料或多或少都要進行排序。儲存此資料最有效率的排序演算法是哪個?為什麼? 記錄是以隨意順序儲存的。    


答案: 當列表部分排序時,插入排序提供了比泡泡排序和選擇排序更好的有效。因此David應使用插入排序演算法。


殼排序演算法: 只要此列表已經部分排序且造成平均用例中的無效解決方案,則插入演算法是高效演算法。 為了克服此限制,電腦科學家D.L. Shell提議改進插入排序演算法。 新的演算法稱為殼(Shell)排序,是按照他的姓名命名的。


殼排序: 通過按若干位置的距離形成多個子列表分隔元素並進行比較來改進插入排序算 每個子列表應用插入排序使元素朝著其正確的位置移動 幫助元素快速靠近正確的位置,因此減少了比較的次數


小結
在本章中,你已經學到: 排序是按照某些預定義的順序或關鍵值排列資料的過程。 此順序可以是升序或 降序。 用於排序資料有各種排序演算法。 其中一些如下: 泡排序 選擇排序 插入排序 殼排序 合併排序 快速排序 堆排序

若要選擇合適的演算法,您需要考慮以下內容: 執行時間 儲存空間 程式設計工作 氣泡排序和選擇排序演算法具有二次方程增長階,且因此僅適用於排序小的列表。 插入排序執行不同次數的比較,這取決於最初的元素分階。 當元素已經處於排 序階,則插入排序需要進行極少比較。 如果需要排序的列表幾乎已經排序,則插入排序比氣泡排序和選擇排序更有效率。

通過比較按若干位置的距離分隔的元素,殼排序改善了插入排序 這幫助元素快 速靠近正確的位置,因此減少了比較的次數。


/**********************************************************/

/*描述:編寫程式將10個學生的得分儲存到陣列中。通過使用氣泡排序演算法,來排序陣列中的元素,排序陣列後,顯示排序後陣列的元素*/
using System;

class List
{
	//定義長度為20的整型陣列
	private int[]a=new int[20];	//20是最大長度.
	
	//陣列的個數
	private int n;
	//定義一個方法讀取資料元素到陣列
	public void read()
	{
			//獲得
			while(true)
			{
				Console.WriteLine("請輸入陣列元素的個數<20之內>:");
				string s=Console.ReadLine();
				n=Int32.Parse(s);//轉換為整型.Convert.ToInt32(s)
				if(n<=20)
					break;	//跳出迴圈
				else
					Console.WriteLine("\n陣列只能夠容納20個數組元素.\n");	
			}//while結束.
			Console.WriteLine("");
			Console.WriteLine("----------------------------------");
			Console.WriteLine("-----請輸入陣列元素---------------");
			Console.WriteLine("----------------------------------");
			//使用者將數句元素輸入陣列
			for(int i=0;i<n;i++)
			{
				Console.Write("<"+(i+1)+">");
				string s1=Console.ReadLine();
				a[i]=Int32.Parse(s1);	
			}//<1>20 <2>20 <3>90
	}
			
	//*************************顯示陣列元素*************************
	public void display()
	{
		Console.WriteLine("");
		Console.WriteLine("-------------------------------------------");
		Console.WriteLine("------------排序過後的元素-----------------");
		Console.WriteLine("-------------------------------------------");	
		
		for(int j=0;j<n;j++)
		{
			Console.WriteLine(a[j]);	
		}
	}
	/***************氣泡排序方法***************************/
	public void BubbleSortArray()
	{
		//圈數1--->n-1
		for(int i=1;i<=n-1;i++)	//i:1;不是陣列下標,是通道次數
		{
			//裡面做的工作是兩個相鄰數字的比較;如果不符合升序排列,則交換.j指陣列下標.
			for(int j=0;j<n-i;j++)	//注意:比較n-i次
			{
				if(a[j]>a[j+1])	//則說明不符合升序排列,需要交換
				{
					int temp;
					temp =a[j];
					a[j]=a[j+1];
					a[j+1]=temp;	
				}
			}//內層交換結束
		}//圈數迴圈結束.
	}
	/******************Main()方法*********************/
	public static void Main(string[]args)
	{
		List myList=new List();
		myList.read();	//讀取資料元素
		
		myList.BubbleSortArray();	//呼叫氣泡排序演算法
		myList.display();				  //顯示陣列元素
		Console.WriteLine("\n\n按任意鍵退出.");
		Console.Read();
	}
}

--------------------------

/*
描述:使用選擇排序,來排列包含10個學生得分的整數陣列,升序排列.
*/
using System;

class Selection
{
	//定義陣列的大小
	private int[]a=new int[20];		
	//陣列元素的個數.
	private int n;
	//定義接受陣列元素的函式 
	void read()
	{
		while(true)
		{
			Console.WriteLine("請輸入陣列元素的個數:");
			string s=Console.ReadLine();
			n=Int32.Parse(s);
			if(n<=20)
				break;
			else
				Console.WriteLine("\n陣列只能夠接收20個元素.\n");
		}
		Console.WriteLine("");
		Console.WriteLine("---------------------------------");
		Console.WriteLine("----------請輸入陣列元素---------");
		Console.WriteLine("---------------------------------");
		//使用者輸入資料
		for(int i=0;i<n;i++)
		{
			Console.Write("<"+(i+1)+">");
			string	s1=Console.ReadLine();
			a[i]=Int32.Parse(s1);
		}	
	}
	//顯示陣列內容的函式
	void display()
	{
		Console.WriteLine("");
		Console.WriteLine("---------------------------------");
		Console.WriteLine("----------排序後的陣列元素-------");
		Console.WriteLine("---------------------------------");
		for(int j=0;j<n;j++)
		{
			Console.WriteLine(a[j]);
		}
	}
/*
	選擇排序演算法:每次選擇最小值,將其依次往前排;藉助於下標標記來實現.
*/
	public void SelectionSortArray()
	{
		//外面進行了n-1圈
		for(int i=0;i<n-1;i++)
		{
			//定義個指示最小值標記的變數
			int min_index=i;
			//查詢選擇最小值所對應的標記(下標)
			for(int j=i+1;j<=n-1;j++)
			{
				//判斷如果有值比,最小值下標對應的數還小,則將該值對應的下標給min_index
				if(a[j]<a[min_index])
					min_index=j;
			}//結束尋找最小值下標
			//交換:a[i]<-->a[min_index]
			swap(i,min_index);	//呼叫交換方法.
		}	
	}
	//交換兩個值的方法
	public void swap(int x,int y)
	{
		int temp;
		temp=a[x];
		a[x]=a[y];
		a[y]=temp;
	}
	//類的主方法
	public static void Main()
	{
		Selection sec=new Selection();
		sec.read();
		sec.SelectionSortArray();
		sec.display();
		Console.WriteLine("\n\n請按任意鍵結束!.");
		Console.Read();	
	}
}

---------------------

/*
描述:使用插入排序,來排列包含10個學生得分的整數陣列。
*/
using System;

class Insertion
{
	//定義陣列的大小
	private int[]a=new int[20];		
	//陣列元素的個數.
	private int n;
	//定義接受陣列元素的函式 
	void read()
	{
		while(true)
		{
			Console.WriteLine("請輸入陣列元素的個數:");
			string s=Console.ReadLine();
			n=Int32.Parse(s);
			if(n<=20)
				break;
			else
				Console.WriteLine("\n陣列只能夠接收20個元素.\n");
		}
		Console.WriteLine("");
		Console.WriteLine("---------------------------------");
		Console.WriteLine("----------請輸入陣列元素---------");
		Console.WriteLine("---------------------------------");
		//使用者輸入資料
		for(int i=0;i<n;i++)
		{
			Console.Write("<"+(i+1)+">");
			string	s1=Console.ReadLine();
			a[i]=Int32.Parse(s1);
		}	
	}
	//顯示陣列內容的函式
	void display()
	{
		Console.WriteLine("");
		Console.WriteLine("---------------------------------");
		Console.WriteLine("----------排序後的陣列元素-------");
		Console.WriteLine("---------------------------------");
		for(int j=0;j<n;j++)
		{
			Console.WriteLine(a[j]);
		}
	}
	//****使用插入排序的方法
public void InsertionSortArray()
{
		//重複n-1次來將為排序列表資料放入已排序列表
		for(int i=1;i<n;i++)
		{
		int temp=a[i];
		int j=i-1;
		//如果j>=0或大於臨時值,則執行如下操作
		while((j>=0)&&(a[j]>temp))
		{
			a[j+1]=a[j];
			j--;	
		}
		a[j+1]=temp;
	}
}
	//交換兩個值的方法
	public void swap(int x,int y)
	{
		int temp;
		temp=a[x];
		a[x]=a[y];
		a[y]=temp;
	}
	//類的主方法
	public static void Main()
	{
		Insertion sec=new Insertion();
		sec.read();
		sec.InsertionSortArray();
		sec.display();
		Console.WriteLine("\n\n請按任意鍵結束!.");
		Console.Read();	
	}
}


------------------------------------------------------------------------

/*
描述:使用插入排序,來排列包含10個學生得分的整數陣列。
*/
using System;

class ShellSorter
{	
	//陣列元素的個數.
	private static int n=0;
	//定義陣列的大小
	private int[]a;		
	//定義接受陣列元素的函式 
	void read()
	{
		while(true)
		{
			Console.WriteLine("請輸入陣列元素的個數:");
			string s=Console.ReadLine();
			n=Int32.Parse(s);
			a=new int[n];
			if(n<=20)
				break;
			else
				Console.WriteLine("\n陣列只能夠接收20個元素.\n");
		}
		Console.WriteLine("");
		Console.WriteLine("---------------------------------");
		Console.WriteLine("----------請輸入陣列元素---------");
		Console.WriteLine("---------------------------------");
		//使用者輸入資料
		for(int i=0;i<n;i++)
		{
			Console.Write("<"+(i+1)+">");
			string	s1=Console.ReadLine();
			a[i]=Int32.Parse(s1);
		}	
	}
	//顯示陣列內容的函式
	void display()
	{
		Console.WriteLine("");
		Console.WriteLine("---------------------------------");
		Console.WriteLine("----------排序後的陣列元素-------");
		Console.WriteLine("---------------------------------");
		for(int j=0;j<n;j++)
		{
			Console.Write("  "+a[j]);
		}
	}
	//****使用希爾排序的方法
        public void ShellSort()
        {        		
            for (int step = a.Length/ 2; step >= 1; step = step / 2)
            {
                for (int i = step; i < a.Length; i+=step)                
                {
                    int temp = a[i];
                    int j = i - step;
                    while (j >= 0 && temp < a[j])
                    {
                        a[j + step] = a[j];
                        j-=step;
                    }
                    a[j + step] = temp;
                }
            }
        }
	//交換兩個值的方法
	public void swap(int x,int y)
	{
		int temp;
		temp=a[x];
		a[x]=a[y];
		a[y]=temp;
	}
	//類的主方法
	public static void Main()
	{
		ShellSorter sec=new ShellSorter();
		sec.read();
		sec.ShellSort();
		sec.display();
		Console.WriteLine("\n\n請按任意鍵結束!.");
		Console.Read();	
	}
}