1. 程式人生 > >資料結構與演算法基礎-01-二分查詢

資料結構與演算法基礎-01-二分查詢

二分查詢

注:本題目源自《浙江大學-資料結構》課程,題目要求實現二分查詢演算法。

函式介面定義

Position BinarySearch( List L, ElementType X );

其中List結構定義如下:

typedef int Position;
typedef struct LNode *List;
struct LNode {
    ElementType Data[MAXSIZE];
    Position Last; /* 儲存線性表中最後一個元素的位置 */
};

並且L是使用者傳入的一個線性表,其中**ElementType元素可以通過

>、==、<**進行比較,並且題目保證傳入的資料是遞增有序的。函式BinarySearch要查詢X在Data中的位置,即陣列下標(注意:元素從下標1開始儲存)。找到則返回下標,否則返回一個特殊的失敗標記NotFound

測試程式樣例 (C語言版)##

#include <stdio.h>
#include <stdlib.h>

#define MAXSIZE 10
#define NotFound 0
typedef int ElementType;

typedef int Position;
typedef struct LNode *List;
struct LNode {
    ElementType Data[MAXSIZE];
    Position Last; /* 儲存線性表中最後一個元素的位置 */
};

List ReadInput(); /* 裁判實現,細節不表。元素從下標1開始儲存 */
Position BinarySearch( List L, ElementType X );

int main()
{
    List L;
    ElementType X;
    Position P;

    L = ReadInput();
    scanf("%d", &X);
    P = BinarySearch( L, X );
    printf("%d\n", P);

    return 0;
}

/* 你的程式碼將被嵌在這裡 */

輸入樣例1:

5
12 31 55 89 101
31

輸出樣例1:

2

輸入樣例2:

3
26 78 233
31

輸出樣例2:

0

程式程式碼:


Position BinarySearch( List Tbl, ElementType K )
{
	if(Tbl==NULL)
		return NotFound;
	int low=1,high=Tbl->Last;
	int mid;
	while(low<=high)//low一定小於等於high 如下標為1、2、3 要查詢的是下標為1的數,第一次是比較下標為2的數,不符合 high就變成了1,如果寫low<high就會返回錯誤的結果
	{
		mid=(low+high)/2;
		if(Tbl->Data[mid]==K)
			return mid;
		else if(Tbl->Data[mid]>K)
			high=mid-1;
		else
			low=mid+1;
	}
	return NotFound;
}

##測試結果與題目裁判結果相符

##二分查詢總結:

  • 概念
    二分查詢也稱折半查詢(Binary Search),它是一種效率較高的查詢方法。但是,折半查詢要求線性表必須採用順序儲存結構,而且表中元素按關鍵字有序排列

    該演算法充分利用了元素間的次序關係,採用分治策略,可在最壞的情況下用O(log n)完成搜尋任務。它的基本思想是,將n個元素分成個數大致相同的兩半,取a[n/2]與欲查詢的x作比較,如果x=a[n/2]則找到x,演算法終止。如 果x小於a[n/2],則我們只要在陣列a的左半部繼續搜尋x(這裡假設陣列元素呈升序排列)。如果x大於a[n/2],則我們只要在陣列a的右 半部繼續搜尋x。
    
  • 查詢過程
    首先,假設表中元素是按升序排列,將表中間位置記錄的關鍵字與查詢關鍵字比較,如果兩者相等,則查詢成功;否則利用中間位置記錄將表分成前、後兩個子表,如果中間位置記錄的關鍵字大於查詢關鍵字,則進一步查詢前一子表,否則進一步查詢後一子表。重複以上過程,直到找到滿足條件的記錄,使查詢成功,或直到子表不存在為止,此時查詢不成功。

  • 演算法要求
    1、線性表必須採用順序儲存結構
    2、表中元素按照關鍵字有序排列(升序或者降序)

  • 比較次數
    計算公式: a &lt; l o g 2 n &lt; b ( a , b , n ) a&lt;log2n&lt;b (a,b,n為正整數)
    當順序表有n個關鍵字時:
    查詢失敗時,至少比較a次關鍵字;查詢成功時,最多比較關鍵字次數是b。
    注意:a,b,n均為正整數

  • Python原始碼


def bin_search(data_list, val):    
    low = 0                         # 最小數下標    
    high = len(data_list) - 1       # 最大數下標    
    while low <= high:        
        mid = (low + high) // 2     # 中間數下標        
        if data_list[mid] == val:   # 如果中間數下標等於val, 返回            
            return mid        
        elif data_list[mid] > val:  # 如果val在中間數左邊, 移動high下標            
            high = mid - 1        
        else:                       # 如果val在中間數右邊, 移動low下標            
            low = mid + 1    
    return # val不存在, 返回None
ret = bin_search(list(range(1, 10)), 3)
print(ret)
  • C/C++遞迴實現

#include<iostream>
using namespace std;
int a[100]={1,2,3,5,12,12,12,15,29,55};//陣列中的數(由小到大)
int k;//要找的數字
int found(int x,int y)
{
    int m=x+(y-x)/2;
    if(x>y)//查詢完畢沒有找到答案,返回-1
        return -1;
    else
    {
        if(a[m]==k)
            return m;//找到!返回位置.
        else if(a[m]>k)
            return found(x,m-1);//找左邊
         else
            return found(m+1,y);//找右邊
    }
}
int main()
    {
        cin>>k;//輸入要找的數字c語言把cin換為scanf即可
        cout<<found(0,9);//從陣列a[0]到a[9]c語言把cout換為printf即可
        return 0;
    }

##函式執行時間計時程式模板

#include <iostream>
#include <time.h>   //For using the system Timer
#include <stdlib.h>

using namespace std;

clock_t start, stop;   //Define the start and stop of the timer

int PrintN(int n)
{
	int i = 0;
	for (i; i < n; i++) {
		std::cout << i << endl;
	}
	return 0;
}

int main()
{
	int n;
	std::cin>>n;
	start = clock();
	PrintN(n);
	stop = clock();
	double duration = ((double)(stop - start)) / CLK_TCK;   //To calculate the time that this function used

	std::cout << duration << endl;
	system("PAUSE");    //Pause the system for a moment 

	return 0;

}