哨兵线性搜索算法浅析与Python,C#实践Demo

如题:

在数组A[]中搜索给定值foundNum,其中length是A[]的长度

  • 常规线性搜索
1.令索引i初始值为0,按次序依次赋值到n-1;
(a)如果A[i]==foundNum,返回当前i;
2.返回-1;代表没找到

在常规线性搜索的第1步实际有两个测试:一个是判断索引是否越界,二是判断是否与foundNum相等。也就是在遍历的时候,实际上每次都要判断一次是否越界。

  • 哨兵线性搜索

针对常规线性搜索的每次都要判断越界的这个操作,我们可进行如下优化,首先将A[]的最后一个元素改成foundNum,那么就“确保肯定能搜到”foundNum值了,下面就可以只判断是否当前值与foundNum相等,如果不等,就“无脑”增加索引值,而避开了判断索引是否越界的这个操作,那么,还有个问题,就是万一最后一个值恰好就是foundNum,该如何处理,很简单,现在就只需要一次判断最后一个值 是否就是foundNum就可以了。最后根据i<n-1或者A[n-1]==foundNum来给出结果,如果这两个条件都不满足,那么就返回-1,代表没找到。

1.将A[length-1]的值保存在last中,令A[length-1]=foundNum;
2.i赋值为0;
3.只要A[i]!=foundNum,就自增i;
4.否则,A[length-1]重新赋值为last
5.如果i<length-1 或者A[length-1]==foundNum,返回i
    否则,返回-1,代表没找到

C#代码进行验证:

    class Program
    {
      public static void Main()
        {
            long max = 1000000000;
            int result;
            long[] a = new long[max];
            for(long i = 0; i < a.Length; i++)
            {
                a[i] = i;
            }
            
            var stpw = new Stopwatch();
            stpw.Start();
            result=BetterLinearSearch(a,a.Length, max);
            stpw.Stop();
            Console.WriteLine("BetterLinearSearch result:{0},time:{1}", result, stpw.ElapsedMilliseconds);

            var stpw0 = new Stopwatch();
            stpw0.Start();
            result = SentinelLinearSearch(a,a.Length, max);
            stpw0.Stop();
            Console.WriteLine("SentinelLinearSearch result:{0},time:{1}", result, stpw0.ElapsedMilliseconds);
        }

        public static int BetterLinearSearch(long[] a,int length,long foundNum)
        {
           for(int i = 0; i < length; i++)
            {
                if (a[i] == foundNum) return i;

            }
            return -1;
        }
        public static int SentinelLinearSearch(long[] a,int length,long foundNum)
        {
            var last = a[length-1];
            a[length-1] = foundNum;
            int i = 0;
            do
            {
                if (a[i] != foundNum)
                {
                    i += 1;
                }
                else
                {
                    a[length-1] = last;
                    if (i < length-1 || a[length-1] == foundNum) return i;
                    else return -1;
                }
            }
            while (true);
            
        }
     
    }

image-20211225235045339

python代码进行实践:

import time
max=100000000
a=list(range(max))
def linearSearch(a,num,findNum):
    i=0
    while(i<len(a)):  #不用 for i in range(len(a)) 是因为python中的for并没有索引递增
        			#然后判断是否越界,而是直接在容器/迭代器中进行遍历
        if(a[i]==findNum):
            return i;
        else:
            i+=1;
    return -1;

def sentinelLineSearch(a,num,findNum):
    last=a[-1]
    a[-1]=findNum
    i=0
    while(True):
        if(a[i]!=findNum):
            i+=1
        else:
            a[-1]=last
            if(i<(num-1) or a[num-1]==findNum):
                return i 
            else:
                return -1 

tim=time.time()
b=linearSearch(a,len(a),len(a))
print("LinearSearch result is {0}, time is {1}".format(b,time.time()-tim))
tim=time.time()
b=sentinelLineSearch(a,len(a),len(a))
print("SentinelLinearSearch result is {0},time is {1}".format(b,time.time()-tim))

image-20211226003852640

实际代码也确实验证了哨兵线性搜索算法比常规线性搜索算法更高效些。

posted @ 2021-12-25 23:52  JohnYang819  阅读(81)  评论(0编辑  收藏  举报