zoukankan      html  css  js  c++  java
  • 数据结构笔记-----查找

    查找的概念



    搜索引擎用的是静态查找




    代码(静态查找and动态查找)


    <strong><span style="font-size:18px;">#include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    #include "SeqList.h"
    
    #define SIZE 20
    /* run this program using the console pauser or add your own getch, system("pause") or input loop */
    
    void print_array(int a[], int len)
    {
        int i = 0;
        
        for(i=0; i<len; i++)
        {
            printf("%d, ", a[i]);
        }
        
        printf("
    ");
    }
    
    int static_search(int a[], int len, int key)
    {//静态查找 
        int ret = -1;
        int i = 0;
        
        for(i=0; i<len; i++)
        {
            if( a[i] == key )
            {
                ret = i;
                break;
            }
        }
        
        return ret;
    }
    
    void print_list(SeqList* list)
    {
        int i = 0;
        
        for(i=0; i<SeqList_Length(list); i++)
        {
            printf("%d, ", (int)SeqList_Get(list, i));
        }
        
        printf("
    ");
    }
    
    int dynamic_search(SeqList* list, int key)
    {//动态查找 
        int ret = -1;
        int i = 0;
        
        for(i=0; i<SeqList_Length(list); i++)
        {
            if( (int)SeqList_Get(list, i) == key )
            {
                ret = i;
                
                SeqList_Delete(list, i);
                
                break;
            }
        }
        
        return ret;
    }
    
    int main(int argc, char *argv[]) 
    {
        SeqList* list = SeqList_Create(SIZE);
        int a[SIZE] = {0};
        int i = 0;
        int key = 0;
        int index = 0;
        
        srand((unsigned int)time(NULL));
        
        for(i=0; i<SIZE; i++)
        {
            a[i] = rand() % 100;
            SeqList_Insert(list, (SeqListNode*)(rand() % 100), i);
            //加入链表 动态查找 
        }
        
        key = rand() % 100;
        
        printf("Static Search Demo
    ");
        printf("Key: %d
    ", key);
        printf("Array: 
    ");
        print_array(a, SIZE);
        
        index = static_search(a, SIZE, key);
        
        if( index >= 0 )
        {
            printf("Success: a[%d] = %d
    ", index, a[index]);
        }
        else
        {
            printf("Failed!
    ");
        }
        
        printf("Dynamic Search Demo
    ");
        printf("Key: %d
    ", key);
        printf("List: 
    ");
        print_list(list);
        
        index = dynamic_search(list, key);
        
        if( index >= 0 )
        {
            printf("Success: list[%d] = %d
    ", index, key);
        }
        else
        {
            printf("Failed!
    ");
        }
        
        print_list(list);
        
    	return 0;
    }</span></strong>


    小结



    顺序表和有序表查找

    顺序表查找



    <strong><span style="font-size:18px;">#include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    
    #define SIZE 20
    /* run this program using the console pauser or add your own getch, system("pause") or input loop */
    
    void print_array(int a[], int begin, int end)
    {
        int i = 0;
        
        for(i=begin; i<=end; i++)
        {
            printf("%d, ", a[i]);
        }
        
        printf("
    ");
    }
    
    int another_search(int a[], int len, int key)
    {
        int ret = len;
        
        a[0] = key;
        //优化顺序查找 
        while( a[ret] != key )
        {//只需比较一次,提高效率 
            ret--;
        }
        
        return ret;
    }
    
    int main(int argc, char *argv[]) 
    {
        int a[SIZE + 1] = {0};
        int i = 0;
        int key = 0;
        int index = 0;
        
        srand((unsigned int)time(NULL));
        
        for(i=1; i<=SIZE; i++)
        {
            a[i] = rand() % 100;
        }
        
        key = rand() % 100;
        
        printf("Another Search Demo
    ");
        printf("Key: %d
    ", key);
        printf("Array: 
    ");
        print_array(a, 1, SIZE);
        
        index = another_search(a, SIZE, key);
        
        if( index > 0 )
        {
            printf("Success: a[%d] = %d
    ", index, a[index]);
        }
        else
        {
            printf("Failed!
    ");
        }
        
    	return 0;
    }</span></strong>


    二分查找(有序查找的一种)







    插值查找


    插值查找的速度比二分查找快,但是插值查找需要进行浮点数计算,因此,从稳定性上,插值不如二分查找

    小结



    二分查找代码


    <strong><span style="font-size:18px;">#include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    
    #define SIZE 20
    /* run this program using the console pauser or add your own getch, system("pause") or input loop */
    
    void println(int array[], int len)
    {
        int i = 0;
        
        for(i=0; i<len; i++)
        {
            printf("%d ", array[i]);
        }
        
        printf("
    ");
    }
    
    void swap(int array[], int i, int j)
    {
        int temp = array[i];
        
        array[i] = array[j];
        
        array[j] = temp;
    }
    
    void SelectionSort(int array[], int len) // O(n*n)
    {
        int i = 0;
        int j = 0;
        int k = -1;
        
        for(i=0; i<len; i++)
        {
            k = i;
            
            for(j=i; j<len; j++)
            {
                if( array[j] < array[k] )
                {
                    k = j;
                }
            }
            
            swap(array, i, k);
        }
    }
    //二分查找 
    int binary_search(int a[], int low, int high, int key) // O(logn)
    {
        int ret = -1;
        
        if( low <= high )
        {
            int mid = (low + high) / 2;
            
            if( a[mid] == key )
            {
                ret = mid;
            }
            else if( key < a[mid] )
            {
                ret = binary_search(a, low, mid-1, key);
            }
            else if( key > a[mid] )
            {
                ret = binary_search(a, mid+1, high, key);
            }
        }
        
        return ret;
    }
    //二分查找 
    int binary_search_ex(int a[], int low, int high, int key) // O(logn)
    {//循环代替递归  
        int ret = -1;
        
        while( low <= high )
        {
            int mid = (low + high) / 2;
            
            if( a[mid] == key )
            {
                ret = mid;
                break;
            }
            else if( key < a[mid] )
            {
                high = mid - 1;
            }
            else if( key > a[mid] )
            {
                low = mid + 1;
            }
        }
        
        return ret;
    }
    
    int interpolation_search(int a[], int low, int high, int key)
    {//插值查找 
        int ret = -1;
        
        while( (low <= high) && (a[low] <= key) && (key <= a[high]) )
        {
            float fx = 1.0f * (key - a[low]) / (a[high] - a[low]);
            int mid = low + fx * (high - low);
            
            if( a[mid] == key )
            {
                ret = mid;
                break;
            }
            else if( key < a[mid] )
            {
                high = mid - 1;
            }
            else if( key > a[mid] )
            {
                low = mid + 1;
            }
        }
        
        return ret;
    }
    
    int main(int argc, char *argv[]) 
    {
        int a[SIZE] = {0};
        int i = 0;
        int key = 0;
        int index = 0;
        
        srand((unsigned int)time(NULL));
        
        for(i=1; i<=SIZE; i++)
        {
            a[i] = rand() % 100;
        }
        
        key = 50;
        
        printf("Binary Search Demo
    ");
        printf("Key: %d
    ", key);
        printf("Array: 
    ");
        
        SelectionSort(a, SIZE);
        
        println(a, SIZE);
        
        index = interpolation_search(a, 0, SIZE-1, key);
        
        if( index > 0 )
        {
            printf("Success: a[%d] = %d
    ", index, a[index]);
        }
        else
        {
            printf("Failed!
    ");
        }
        
    	return 0;
    }</span></strong>


    斐波那契数列

    黄金比例又称黄金分割,是指事物各部分间一定的数学比例关系,即将整体一分为二,较大部分与较小部分之比等于整体与较大部分之比,其比值约为1:0.618或1.618:1。

    0.618被公认为最具有审美意义的比例数字,这个数值的作用不仅仅体现在诸如绘画、雕塑、音乐、建筑等艺术领域,而且在管理、工程设计等方面也有着不可忽视的作用。因此被称为黄金分
    割。

    大家记不记得斐波那契数列:1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89…….(从第三个数开始,后边每一个数都是前两个数的和)

    然后我们会发现,随着斐波那契数列的递增,前后两个数的比值会越来越接近0.618,利用这个特性,我们就可以将黄金比例运用到查找技术中。


    代码


    <strong><span style="font-size:18px;">  
    #include "stdafx.h"  
    #include <memory>  
    #include  <iostream>  
    using namespace std;  
      
    const int max_size=20;//斐波那契数组的长度  
      
    /*构造一个斐波那契数组*/   
    void Fibonacci(int * F)  
    {  
        F[0]=0;  
        F[1]=1;  
        for(int i=2;i<max_size;++i)  
            F[i]=F[i-1]+F[i-2];  
    }  
      
    /*定义斐波那契查找法*/    
    int Fibonacci_Search(int *a, int n, int key)  //a为要查找的数组,n为要查找的数组长度,key为要查找的关键字  
    {  
      int low=0;  
      int high=n-1;  
        
      int F[max_size];  
      Fibonacci(F);//构造一个斐波那契数组F   
      
      int k=0;  
      while(n>F[k]-1)//计算n位于斐波那契数列的位置  
          ++k;  
      
      int  * temp;//将数组a扩展到F[k]-1的长度  
      temp=new int [F[k]-1];  
      memcpy(temp,a,n*sizeof(int));  
      
      for(int i=n;i<F[k]-1;++i)  
         temp[i]=a[n-1];  
        
      while(low<=high)  
      {  
        int mid=low+F[k-1]-1;  
        if(key<temp[mid])  
        {  
          high=mid-1;  
          k-=1;  
        }  
        else if(key>temp[mid])  
        {  
         low=mid+1;  
         k-=2;  
        }  
        else  
        {  
           if(mid<n)  
               return mid; //若相等则说明mid即为查找到的位置  
           else  
               return n-1; //若mid>=n则说明是扩展的数值,返回n-1  
        }  
      }    
      delete [] temp;  
      return -1;  
    }  
      
    int _tmain(int argc, _TCHAR* argv[])  
    {  
        int a[] = {0,16,24,35,47,59,62,73,88,99};  
        int key=100;  
        int index=Fibonacci_Search(a,sizeof(a)/sizeof(int),key);  
        cout<<key<<" is located at:"<<index;  
        system("PAUSE");  
        return 0;  
    }  </span></strong>

    斐波那契查找的核心是:
    1)当key=a[mid]时,查找成功;
    2)当key<a[mid]时,新的查找范围是第low个到第mid-1个,此时范围个数为F[k-1] - 1个,即数组左边的长度,所以要在[low, F[k - 1] - 1]范围内查找;
    3)当key>a[mid]时,新的查找范围是第mid+1个到第high个,此时范围个数为F[k-2] - 1个,即数组右边的长度,所以要在[F[k - 2] - 1]范围内查找。





    线性索引查找

    索引的概念


    线性索引












    小结




    思考:


    一、数组中一个只出现一次的整数

    题目:一个数组中,有一个数字只出现一次,其他数字都出现两次,写出程序找出这个数字。

    思路:利用异或运算,如果是两个相同的数,那么他们的结果就是0,剩下的就是只出现一次的数。

    代码如下:

    <strong><span style="font-size:18px;">#include <stdio.h>  
      
    //find a number,which appearing once in an array  
    int FindNumAppearOnce(int arr[], int iLen)  
    {  
        int iNumAppearOnce;  
      
        iNumAppearOnce = arr[0];  
        for(int i = 1; i < iLen; i++)  
            iNumAppearOnce ^= arr[i];  
      
        return iNumAppearOnce;  
    }  
      
    int main(void)  
    {  
        int arr[] = {1,2,2,3,3,4,4};  
        printf("%d
    ",FindNumAppearOnce(arr, 7));  
        return 0;  
    }  </span></strong>

    二、数组中两个只出现一次的整数


    思路:我们要让这两个只出现一次的数分别在两组,然后两组分别异或运算找出只出现一次的数。方法是,首先所有的数进行异或运算,得到的是只出现一次的两个数的异或运算结果。然后根据这个结果中第一次出现1的位(从右开始算),将数组分为两组。为什么可以分成两组?因为异或运算为1就是只出现一次的那两个数的那两个bit位不同,其他的数都抵消了。
    代码如下:

    <strong><span style="font-size:18px;">#include <stdio.h>  
      
    int FindIndexOfBit1(int n)  
    {  
        int indexOfBit1 = 0;  
        while(((1 & n) == 0) && indexOfBit1 < 32){  
            n >>= 1;  
            indexOfBit1++;  
        }  
      
        return indexOfBit1;  
    }  
      
    int IsBit1(int n, int indexOfBit1){  
        n >>= indexOfBit1;  
        return n & 1;  
    }  
      
    //find two number,which appearing once in an array  
    //Input:arr - an array  
    //      iLen - the length of the array  
    //      pNum1 - number 1 founded   
    //      pNum2 - number 2 founded  
    void FindNumAppearOnce(int arr[], int iLen, int *pNum1, int *pNum2)  
    {  
        if(iLen < 2)  
            return;  
      
        //get num1^num2  
        int resultOfExclusiveOr = 0;  
        for(int i = 0; i < iLen; i++)  
            resultOfExclusiveOr ^= arr[i];  
      
        //get index of the first bit  
        int indexOfBit1 = FindIndexOfBit1(resultOfExclusiveOr);  
      
        *pNum1 = *pNum2 = 0;  
        for(int i = 0; i < iLen; i++){  
            if(IsBit1(arr[i], indexOfBit1))  
                *pNum1 ^= arr[i];  
            else  
                *pNum2 ^= arr[i];  
        }  
    }  
      
    int main(void)  
    {  
        int arr[] = {1,5,2,2,3,3,4,4};  
        int a;  
        int b;  
        FindNumAppearOnce(arr, 8, &a, &b);  
        printf("%d %d
    ", a,b);  
        return 0;  
    }  </span></strong>


    三、数组中3个只出现一次的数字
    思路:
    我们要把三个不同的数分开!首先分开两组,一个不同的和两个不同的各位一组。分开的思路:参考http://zhedahht.blog.163.com/blog/static/25411174201283084246412/
    总之:x^a、x^b、x^c三个数字中,只有一个数字的第m位是1。作为它们的区分标准。


    <strong><span style="font-size:18px;">#include <stdio.h>  
      
    //  
    int ValueOfBit1(int iNum)  
    {  
        return iNum & ~(iNum - 1);  
    }  
      
    //  
    void Swap(int *pNum1, int *pNum2)  
    {  
        int iTemp;   
        iTemp = *pNum1;  
        *pNum1 = *pNum2;  
        *pNum2 = iTemp;  
    }  
      
    //  
    void PrintUniqueTwo(int arrNums[], int iLen)  
    {  
        int iXorResult = 0;  
        for(int i = 0; i < iLen; i++)  
            iXorResult ^= arrNums[i];  
      
        int iDiffBit = ValueOfBit1(iXorResult);  
      
        int iNum1, iNum2;  
        iNum1 = iNum2 = 0;  
        for(int i = 0; i < iLen; i++)  
            if(iDiffBit & arrNums[i])  
                iNum1 ^= arrNums[i];  
            else  
                iNum2 ^= arrNums[i];  
      
        printf("%d
    %d
    ", iNum1, iNum2);  
    }  
      
    void PrintUniqueThree(int arrNums[], int iLen)  
    {  
        if(iLen < 3)  
            return;  
      
        //get a ^ b ^ c  
        int iXorResult = 0;  
        for(int i = 0; i < iLen; i++)  
            iXorResult ^= arrNums[i];  
      
        //get fun(fun(x ^ a) ^ fun(x ^ b) ^ fun(x ^ b))  
        int iFunMultiResult = 0;  
        for(int i = 0; i < iLen; i++)  
            iFunMultiResult ^= ValueOfBit1(iXorResult ^ arrNums[i]);  
        iFunMultiResult = ValueOfBit1(iFunMultiResult);  
      
        //get the first unique number  
        int iFirstUniqueNum = 0;  
        for(int i = 0; i < iLen; i++)  
            if(ValueOfBit1(arrNums[i] ^ iXorResult) == iFunMultiResult)  
                iFirstUniqueNum ^= arrNums[i];  
      
        printf("%d
    ", iFirstUniqueNum);  
      
        //move the first unique number to the end of the array  
        for(int i = 0; i < iLen; i++)  
            if(arrNums[i] == iFirstUniqueNum){  
                Swap(&arrNums[i], &arrNums[iLen - 1]);  
                break;  
            }  
      
            PrintUniqueTwo(arrNums, iLen - 1);  
    }  
      
    int main(void)  
    {  
        int arrNums[] = {2,3,4,4,1,3,5,5,0};  
        PrintUniqueThree(arrNums, 9);  
        return 0;  
    }  </span></strong>


    1-1000放在含有1001个元素的数组中,只有唯一的一个元素值重复,其它均只出现
    一次。每个数组元素只能访问一次,设计一个算法,将它找出来;不用辅助存储空
    间,能否设计一个算法实现?
    将1001个元素相加减去1,2,3,……1000数列的和,得到的差即为重复的元素。
     
     int   Find(int   *   a)   
      {   
      int   i;//变量   
      for   (i   =   0   ;i<=1000;i++)   
      {   
      a[1000]   +=   a[i];   
      }   
      a[1000]   -=   (i*(i-1))/2       //i的值为1001   
      return   a[1000];   
      }

    利用下标与单元中所存储的内容之间的特殊关系,进行遍历访问单元,一旦访问过的单
    元赋予一个标记,利用标记作为发现重复数字的关键。代码如下:
    <strong><span style="font-size:18px;">void FindRepeat(int array[], int length)
    {
        int index=array[length-1]-1;
        while ( true )
        {
           if ( array[index]<0 )
               break;
           array[index]*=-1;
           index=array[index]*(-1)-1;
        }
     
        cout<<"The repeat number is "<<index+1<<endl;
    }</span></strong>


    此种方法不非常的不错,而且它具有可扩展性。在坛子上有人提出:
    对于一个既定的自然数 N ,有一个 N + M 个元素的数组,其中存放了小于等于 N 的所有
    自然数,求重复出现的自然数序列{X} 。
     
    对于这个扩展需要,自己在A_B_C_ABC(黄瓜儿才起蒂蒂)的算法的基础上得到了自己的算法
    代码:
    按照A_B_C_ABC(黄瓜儿才起蒂蒂)的算法,易经标记过的单元在后面一定不会再访问到,除非它是重复的数字,也就是说只要每次将重复数字中的一个改为靠近N+M的自然数,让遍历能访问到数组后面的单元,就能将整个数组遍历完。
    代码:
    <strong><span style="font-size:18px;">*/
    void FindRepeat(int array[], int length, int num)
    {
     int index=array[length-1]-1;
     cout<<"The repeat number is ";
     while ( true )
     {
     if ( array[index]<0 )
     {
       num--;
       array[index]=length-num;
       cout<<index+1<<'t';
     }
     
     if ( num==0 )
     {
       cout<<endl;
      return;
     }
     array[index]*=-1;
     index=array[index]*(-1)-1;
     }
    }</span></strong>












  • 相关阅读:
    203. Remove Linked List Elements
    86. Partition List
    143. Reorder List
    876. Middle of the Linked List
    246. Strobogrammatic Number
    202. Happy Number
    数据类型转换
    表达式
    面向对象
    对齐
  • 原文地址:https://www.cnblogs.com/Zyf2016/p/6337833.html
Copyright © 2011-2022 走看看