從表的一端開始,順序掃描表,依次將掃描到的結點關鍵字和給定值(假定為a)相比較,若當前結點關鍵字與a相等,則查找成功;若掃描結束後,仍未找到關鍵字等於a的結點,則查找失敗。
說白了就是,從頭到尾,一個一個地比,找著相同的就成功,找不到就失敗。很明顯的缺點就是查找效率低。
適用於線性表的順序存儲結構和鏈式存儲結構。
int[] aa = { 3, 6, 8, 7, 10, 15, 12, 14, 16, 17, 20, 21 };
for (int i = 0; i < aa.Length; i++)
{
if(8 == aa[i])
{
Console.WriteLine("找到目標元素");
}
}
(1)確定該區間的中點位置:mid=(low+high)/2
min代表區間中間的結點的位置,low代表區間最左結點位置,high代表區間最右結點位置
(2)將待查a值與結點mid的關鍵字(下面用R[mid].key)比較,若相等,則查找成功,否則確定新的查找區間:
如果R[mid].key>a,則由表的有序性可知,R[mid].key右側的值都大於a,所以等於a的關鍵字如果存在,必然在R[mid].key左邊的表中。這時high=mid-1
如果R[mid].key<a,則等於a的關鍵字如果存在,必然在R[mid].key右邊的表中。這時low=mid
如果R[mid].key=a,則查找成功。
(3)下一次查找針對新的查找區間,重復步驟(1)和(2)
(4)在查找過程中,low逐步增加,high逐步減少,如果high<low,則查找失敗。
但是要將表按關鍵字排序。而排序本身是一種很費時的運算,所以二分法比較適用於順序存儲結構。為保持表的有序性,在順序結構中插入和刪除都必須移動大量的結點。因此,二分查找特別適用於那種一經建立就很少改動而又經常需要查找的線性表。
代碼實現:
/// <summary> /// 二分法查找 /// </summary> /// <param name="array">目標數組(已經排序好了)</param> /// <param name="a">查找的數</param> /// <returns>目標數的索引</returns> public int BinarySearch(int[] array, int T) { int low, high, mid; low = 0; high = array.Length - 1; while (low <= high) { mid = (low + high) / 2; if (array[mid] < T) { low = mid + 1; } else if (array[mid]>T) { high = mid - 1; } else { return mid; } } return -1; }
分塊查找(Blocking Search)又稱索引順序查找。它是一種性能介於順序查找和二分查找之間的查找方法
前提條件: 塊內無序塊間有序using System; using System.Collections.Generic; using System.Text; namespace 分塊查找 { class Program { static void Main(string[] args) { int[] aa = { 3, 6, 8, 7, 10, 15, 12, 14, 16, 17, 20, 21 }; for (int i = 0; i < aa.Length; i++) { if (8 == aa[i]) { Console.WriteLine("找到目標元素"); } } int ysnum, zu, ww = 0; for (int aa1 = 0; aa1 < aa.Length; aa1++) Console.Write(aa[aa1] + " "); Console.WriteLine(); Console.WriteLine("元素個數:{0}", aa.Length); ysnum = aa.Length; #region 分塊 Console.Write("請輸入組數:"); zu = Convert.ToInt32(Console.ReadLine()); int d = aa.Length / zu; int[,] fenkuai = new int[zu, d]; Console.WriteLine("分塊如下:"); for (int z = 0; z < zu; z++)//進行分塊 for (int y = 0; y < d; y++) { fenkuai[z, y] = aa[ww]; ww++; } for (int z = 0; z < zu; z++)//輸出分塊 { for (int y = 0; y < d; y++) { Console.Write("{0} ", fenkuai[z, y]); } Console.WriteLine(); } #endregion #region 確定各分塊的索引表 Console.WriteLine("關鍵字:"); int[] suoyin = new int[zu]; int q = 0; int index = 0; for (int z = 0; z < zu; z++) { int y; for (y = 0; y < d; y++) { if (q < fenkuai[z, y]) { q = fenkuai[z, y]; } } //Console.Write("{0} ", q);//輸出索引表 ////建立索引表 if (index < zu) { suoyin[index] = q; } index++; } for (int n = 0; n < zu; n++) { Console.Write(suoyin[n] + " "); } #endregion #region 塊內進行順序查找 Console.WriteLine("請輸入要查找的值:"); int kk = Convert.ToInt32(Console.ReadLine()); int pp = shunxu(suoyin, kk); for (int n = 0; n < d; n++) { if (kk == fenkuai[pp, n]) { Console.WriteLine("該數值在元素當中"); } } #endregion Console.ReadLine(); } public static int shunxu(int[] aa, int k) { for (int a = 0; a < aa.Length - 1; a++) { if (k <= aa[a]) { return a; } } return -1; } } } View Code
方法:二分查找塊間 順序查找塊內
二分查找表由"分塊有序"的線性表和索引表組成
1."分塊有序"的線性表
表R[1..n]均分為b塊,前b-1塊中結點個數為 s ,第b塊的結點數小於等於s;每一塊中的關鍵字不一定有序,但前一塊中的最大關鍵字必須小於後一塊中的最小關鍵字,即表是"分塊有序"的。
2.索引表
抽取各塊中的最大關鍵字及其起始位置構成一個索引表ID[l..b],即: ID[i](1≤i≤b)中存放第i塊的最大關鍵字及該塊在表R中的起始位置。由於表R是分塊有序的,所以索引表是一個遞增有序表。
因此采用順序或二分查找索引表,以確定待查結點在哪一塊,由於塊內無序,只能用順序查找
哈希技術是查找和檢索與唯一標識鍵相關信息的最好方法之一。哈希表的基本原理是將給定的鍵值轉換為偏移地址來檢索記錄。
鍵轉換為地址是通過一種關系來完成,就是哈希函數。哈希函數對鍵執行操作,從而給定一個哈希值,該值是代表可以找到該記錄的位置。
哈希法的基本思想是:設置一個長度為m的表T,用一個函數將數據集合中n個記錄的關鍵字盡可能唯一地轉換成0~m-1范圍內的數值
哈希表的沖突現象
兩個不同的關鍵字,由於哈希函數值相同,因而被映射到同一個位置,為沖突。
解決哈希沖突
鏈表法:將所有關鍵字為同義詞的結點鏈接在同一個單鏈表中。即同一位置用單鏈表存儲鍵相同而值不同的記錄。
/// <summary> /// 在哈希表中插入記錄,用鏈表法解決沖突 /// </summary> /// <param name="a"></param> /// <param name="key"></param> /// <param name="Mod"></param> /// <returns></returns> public bool HashInsert(chaintype[] a, int key, int Mod) { int i; i = Hash(key, Mod); chaintype pre; chaintype cur; pre = a[i]; cur = a[i]; while (cur != null && cur.Key != key) { pre = cur; cur = cur.Next; } /*未查找到時插入該記錄在對應的鏈表尾*/ if (cur == null) { cur = new chaintype(); cur.Key = key; cur.Next = null; /*在該鏈插入第一個記錄*/ if (a[i] == null) a[i] = cur; else pre.Next = cur; return true; } return false; } public chaintype HashSearch(chaintype[] a, int key, int Mod) { chaintype p; int i = Hash(key, Mod); p = a[i]; while (p != null && p.Key != key) { p = p.Next; } if (p == null) return null; else return p; }
代碼調用:
searchA.HashInsert(a, 70, 13); searchA.HashInsert(a, 30, 13); searchA.HashInsert(a, 40, 13); searchA.HashInsert(a, 10, 13); searchA.HashInsert(a, 80, 13); searchA.HashInsert(a, 20, 13); searchA.HashInsert(a, 90, 13); searchA.HashInsert(a, 100, 13); searchA.HashInsert(a, 75, 13); searchA.HashInsert(a, 60, 13); searchA.HashInsert(a, 45, 13); Console.WriteLine("請輸入要查找的數字:"); long time1 = System.DateTime.Now.Ticks; int num = Convert.ToInt32(Console.ReadLine()); chaintype p = searchA.HashSearch(a, num, 13); if (p == null) Console.WriteLine("{0}在數據列表中不存在", num); else Console.WriteLine("您查找的關鍵字是:{0}", p.Key); long time2 = System.DateTime.Now.Ticks; Console.WriteLine("哈希表查找用時{0}", time2 - time1);
文章參考
文章摘要: 查找是在大量的信息中尋找一個特定的信息元素,在計算機應用中,查找是常用的基本運算,文中介紹四種查找算法,分別是順序查找、二分查找、二叉排序樹查找和哈希查找。並用JAVA語言編寫了相應程序代碼,比較了查找同一個數據的時間復雜度和空間復雜度。
二分:要求待查找序列是排完序的,即是有序的序列。
哈希:能夠比較好的解決位置沖突的情況下哈希查找都是比較快速的。主要是hash函數的選擇。
二叉排序樹:如果樹比較平衡的情況下,這種查找的復雜度是log(n),但是如果很偏,比如一直都只插入左兒子節點(這樣就和鏈表一樣了),那麼就比較糟糕了。