所謂查找是指根據給定的某個值,在一個給定的數據結構中查找指定元素的過程。
主要得查找技術:線性表查找技術 樹型查找技術 哈希表查找技術
線性表查找技術
順序查找
最簡單的查找方法。基本思想:從表的一端開始,順序掃描線性表,一次獎掃描到的結點的關鍵字和給定值K想比較。
順序查找的效率不高,但下列兩種情況下自能有順序查找。
1.若順序表為無序表
2.采用鏈式存儲結構的線性表
int SeqSearch(SeqList<int> R, int Key) { int i; R.Data[R.GetLength()] = Key; for (i = 0; R.Data[i] != Key; i++) ; if (i > R.Maxsize - 2) return -2; else return i; }
二分查找
折半查找 要求線性表是有序表,即表中結點按關鍵字有序,並且用順序表作為表的存儲結構。
int BinSearch(SeqList<int> R, int Key) { int low = 0, high = R.GetLength() - 1, mid; //設置當前查找區間的上下界的初值 while (low <= high) { mid = (low + high) / 2; if (R.Data[mid] == Key) return mid; if (R.Data[mid] > Key) high = mid - 1; else low = mid + 1; } return -1; }
分塊查找
無
哈希表查詢技術
哈希技術是查找和檢索與唯一標識鍵相關信息的最好方法之一。哈希表的基本原理是將給定的鍵值轉換為偏移地址來檢索記錄。
鍵轉換為地址是通過一種關系來完成,就是哈希函數。哈希函數對鍵執行操作,從而給定一個哈希值,該值是代表可以找到該記錄的位置。
哈希法的基本思想是:設置一個長度為m的表T,用一個函數將數據集合中n個記錄的關鍵字盡可能唯一地轉換成0~m-1范圍內的數值.
哈希表的沖突現象
兩個不同的關鍵字,由於哈希函數值相同,因而被映射到同一個位置,為沖突。
解決哈希沖突
鏈表法:將所有關鍵字為同義詞的結點鏈接在同一個單鏈表中。即同一位置用單鏈表存儲鍵相同而值不同的記錄。
Search
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DataStructure { public interface IListDS<T> { int GetLength(); //求長度 void Clear(); //清空操作 bool IsEmpty(); //判斷線性表是否為空 bool IsFull(); //判斷數據表是否已滿 void Append(T item); //附加操作 void Insert(T item, int i); //插入操作 T Delete(int i); //刪除操作 T GetElement(int i); //取表元 int Locate(T value); //按值查找 void Reserve(); //倒置 } public class SeqList<T> : IListDS<T> { private int maxsize; //順序表的容量 private T[] data; //數組,用於存儲數據表中的數據元素 private int last; //指示數據表中最后一個元素的位置 //索引器 public T this[int index] { get { return data[index]; } set { data[index] = value; } } public T[] Data { get { return data; } set { data = value; } } //屬性 最后一個元素的位置 public int Last { get { return last; } } //屬性 容量 public int Maxsize { get { return maxsize; } set { maxsize = value; } } //構造函數 public SeqList(int size) { data = new T[size]; maxsize = size; last = -1; } public int GetLength() { return last + 1; } public void Clear() { last = -1; } public bool IsEmpty() { if (last == -1) return true; else return false; } public bool IsFull() { if (last == maxsize - 1) return true; else return false; } public void Append(T item) { if (IsFull()) { Console.WriteLine("List is full !"); return; } data[++last] = item; } public void Insert(T item, int i) { if (IsFull()) { Console.WriteLine("List is Full !"); return; } if (i < 1 || i > last + 2) { Console.WriteLine("Postion is Error !"); return; } if (i == last + 2) { data[i - 1] = item; } else { for (int j = last; j >= i - 1; j--) { data[j + 1] = data[j]; } data[i - 1] = item; } ++last; } public T Delete(int i) { T tem = default(T); if (IsEmpty()) { Console.WriteLine("List is Empty !"); return tem; } if (i < 1 || i > last + 1) { Console.WriteLine("Postion is Error !"); return tem; } if (i == last + 1) { tem = data[last--]; return tem; } else { tem = data[i - 1]; for (int j = i; j <= last; j++) { data[j] = data[j + 1]; } } --last; return tem; } public T GetElement(int i) { if (IsEmpty() || i < 1 || i > last + 1) { Console.WriteLine("List is Empty or Postion is Error !"); return default(T); } return data[i - 1]; } public int Locate(T value) { if (IsEmpty()) { Console.WriteLine("List is Empty !"); return -1; } int i = 0; for (i = 0; i <= last; i++) { if (value.Equals(data[i])) break; } if (i > last) { return -1; } return i; } public void Reserve() { T tem; int len = GetLength(); for (int i = 0; i <= len / 2; i++) { tem = data[i]; data[i] = data[len - 1]; data[len - 1] = tem; } } /// <summary> /// 將兩個升序整型順序表合並成一個升序順序表 /// 思路:依次掃描La Lb中的元素,比較La和Lb中當前元素,將較小的元素值賦值給Lc,如此直到一個被掃描完,然后把未完的那個剩余的元素付給Lc /// </summary> /// <param name="La"></param> /// <param name="Lb"></param> /// <returns></returns> public SeqList<int> Merge(SeqList<int> La, SeqList<int> Lb) { SeqList<int> Lc = new SeqList<int>(La.Maxsize + Lb.Maxsize); int i = 0; int j = 0; while ((i <= La.GetLength() - 1) && (j <= Lb.GetLength() - 1)) { if (La[i] < Lb[j]) { Lc.Append(La[i++]); } else { Lc.Append(Lb[j++]); } } //如果La中還有元素 while (i <= La.GetLength() - 1) { Lc.Append(La[i++]); } //如果Lb中還有元素 while (i < Lb.GetLength() - 1) { Lc.Append(Lb[i++]); } return Lc; } /// <summary> /// 已知順序表La 構造順序表Lb 使其包含La中所有不相同的數據元素 /// 思路: 先把La中的第一個元素付給Lb 然后從La的第二個元素開始 每一個元素與Lb的每一個元素比較 不同則附加到Lb末尾 /// </summary> /// <param name="La"></param> /// <returns></returns> public SeqList<int> Purge(SeqList<int> La) { SeqList<int> Lb = new SeqList<int>(La.Maxsize); Lb.Append(La[0]); for (int i = 1; i <= La.GetLength() - 1; ++i) { int j = 0; for (j = 0; j <= Lb.GetLength() - 1; ++j) { if (La[i].CompareTo(Lb[j]) == 0) { break; } } //沒有相同的元素,把La中的元素附加到Lb if (j > Lb.GetLength() - 1) { Lb.Append(La[i]); } } return Lb; } } /// <summary> /// 定義解決沖突的鏈表的結點類型 /// </summary> public class chaintype { private int key; private chaintype next; public int Key { get { return key; } set { key = value; } } public chaintype Next { get { return next; } set { next = value; } } } public class SearchArithMetic { /// <summary> /// 插入排序 /// </summary> /// <param name="R"></param> public void InsertSort(SeqList<int> R) { for (int i = 1; i < R.Maxsize; i++) { if (R.Data[i] < R.Data[i - 1]) { int temp = R.Data[i]; int j = 0; for (j = i - 1; j >= 0 && temp < R.Data[j]; j--) { R.Data[j + 1] = R.Data[j]; } R.Data[j + 1] = temp; } } } /// <summary> /// 順序查找算法 /// </summary> /// <param name="R"></param> /// <param name="Key"></param> /// <returns></returns> public int SeqSearch(SeqList<int> R, int Key) { int i; R.Data[R.GetLength()] = Key; for (i = 0; R.Data[i] != Key; i++) ; if (i > R.Maxsize - 2) return -2; else return i; } /// <summary> /// 二分查找算法 /// </summary> /// <param name="R"></param> /// <param name="Key"></param> /// <returns></returns> public int BinSearch(SeqList<int> R, int Key) { int low = 0, high = R.GetLength() - 1, mid; //設置當前查找區間的上下界的初值 while (low <= high) { mid = (low + high) / 2; if (R.Data[mid] == Key) return mid; if (R.Data[mid] > Key) high = mid - 1; else low = mid + 1; } return -1; } /// <summary> /// 除模取余法的哈希函數 /// </summary> /// <param name="key"></param> /// <param name="Mod"></param> /// <returns></returns> public int Hash(int key, int Mod) { return key % Mod; } /// <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; } } class Search { /* /// <summary> /// 順序查找 /// </summary> /// <param name="R"></param> /// <param name="Key"></param> /// <returns></returns> public static int SeqSearch(SeqList<int> R, int Key) { int i; R.Data[R.GetLength()] = Key; for (i = 0; R.Data[i] != Key; i++) ; if (i > R.Maxsize - 2) return -2; else return i; } /// <summary> /// 二分查找 /// </summary> /// <param name="R"></param> /// <param name="Key"></param> /// <returns></returns> public static int BinSearch(SeqList<int> R, int Key) { int low = 0, high = R.GetLength() - 1, mid; //設置當前查找區間的上下界的初值 while (low <= high) { mid = (low + high) / 2; if (R.Data[mid] == Key) return mid; if (R.Data[mid] > Key) high = mid - 1; else low = mid + 1; } return -2; } static void Main() { SeqList<int> queue = new SeqList<int>(10); queue.Append(10); queue.Append(20); queue.Append(30); queue.Append(40); queue.Append(50); queue.Append(60); queue.Append(70); queue.Append(80); queue.Append(90); //int location = SeqSearch(queue, 90); int location = BinSearch(queue, 90); Console.WriteLine("您查找的數據為表中第{0}位!", location + 1); Console.ReadKey(); } */ public static void Main() { SeqList<int> numList = null; numList = new SeqList<int>(12); chaintype[] a = new chaintype[13]; char selectFlag; while (true) { Console.WriteLine("請輸入操作選項:"); Console.WriteLine("1.創建順序表"); Console.WriteLine("2.對順序表執行順序查找"); Console.WriteLine("3.對順序表執行二分查找"); Console.WriteLine("4.創建哈希表"); Console.WriteLine("5.在哈希表中查找關鍵字"); Console.WriteLine("6.退出"); selectFlag = Convert.ToChar(Console.ReadLine()); SearchArithMetic searchA = new SearchArithMetic(); switch (selectFlag) { case '1': { numList.Insert(70, numList.GetLength() + 1); numList.Insert(30, numList.GetLength() + 1); numList.Insert(40, numList.GetLength() + 1); numList.Insert(10, numList.GetLength() + 1); numList.Insert(80, numList.GetLength() + 1); numList.Insert(20, numList.GetLength() + 1); numList.Insert(90, numList.GetLength() + 1); numList.Insert(100, numList.GetLength() + 1); numList.Insert(75, numList.GetLength() + 1); numList.Insert(60, numList.GetLength() + 1); numList.Insert(45, numList.GetLength() + 1); Console.WriteLine("已插入順序表的數字是:"); Console.WriteLine("70 30 40 10 80 20 90 100 75 60 45"); break; } case '2': { Console.WriteLine("請輸入要查找的數字:"); long time1 = System.DateTime.Now.Ticks; int num = Convert.ToInt32(Console.ReadLine()); int i = searchA.SeqSearch(numList, num); if (i == -1) Console.WriteLine("{0}在數字列表中不存在", num); else Console.WriteLine("{0}在數字列表中的序號為{1}", num, i); long time2 = System.DateTime.Now.Ticks; Console.WriteLine("順序查找用時{0}", time2 - time1); break; } case '3': { long time1 = System.DateTime.Now.Ticks; new SearchArithMetic().InsertSort(numList); long time2 = System.DateTime.Now.Ticks; Console.WriteLine("請輸入要查找的數字:"); int num = Convert.ToInt32(Console.ReadLine()); long time3 = System.DateTime.Now.Ticks; int i = searchA.BinSearch(numList, num); if (i == -1) Console.WriteLine("{0}在數據列表中不存在", num); else Console.WriteLine("{0}在數字列表中的序號為{1}", num, i + 1); long time4 = System.DateTime.Now.Ticks; Console.WriteLine("排序用時{0}", time2 - time1); Console.WriteLine("二分查找用時{0}", time4 - time3); Console.WriteLine("查找總用時{0}", time4 - time1); break; } case '4': { 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); break; } case '5': { 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); break; } case '6': { return; } } Console.WriteLine("按任意鍵繼續"); Console.ReadLine(); } } } }
注:本文整理自《數據結構(C#語言版)》!!!
