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#语言版)》!!!

posted on 2012-09-03 17:12  YuanSong  阅读(7298)  评论(0编辑  收藏  举报

导航