C# 算法 之 查找算法


所謂查找是指根據給定的某個值,在一個給定的數據結構中查找指定元素的過程。

主要得查找技術:線性表查找技術 樹型查找技術 哈希表查找技術

線性表查找技術

順序查找

最簡單的查找方法。基本思想:從表的一端開始,順序掃描線性表,一次獎掃描到的結點的關鍵字和給定值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#語言版)》!!!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM