1. 程式人生 > >資料結構與演算法實踐 之 二分查詢初識

資料結構與演算法實踐 之 二分查詢初識

      今天起,我要對資料結構和基本的演算法進行一些簡單的複習,並在複習的基礎上對其進行深入的挖掘。這篇文章先對二分查詢進行一個簡要的複習,在之後的文章中會對其進行深入的學習。

      二分查詢又叫折半查詢,是最基本的幾種查詢演算法之一。簡單的看,二分法查詢主要應用於在一個有序數列中進行元素的查詢,其基本思路是,先用我們要查詢的元素與這個有序數列中的中間位置的元素進行比較(在此我們姑且稱這個元素為“中間位置元素”吧,至於這個元素怎麼求我在後面會詳細說明),如果相等,則返回這個“中間位置元素”的值;若待查詢元素小於“中間位置元素”,我們就以中間位置元素為界,在中間位置元素的“左邊”進行查詢,當然,查詢的方式和我們第一步所做的一樣,還是將待查詢元素與中間位置元素進行對比,不過要注意的是,這裡的中間位置元素可不是最初的數列的中間位置的元素,而是在最初的數列的基礎之上,以第一步的“中間位置元素”為界劃分出來的左邊的子數列的中間位置元素。那麼如果待查詢元素大於“中間位置元素”,我們在下一步的折半查詢中就要在“中間位置元素”右側的那部分子數列進行同樣的二分操作。不管是在哪一側的子數列進行查詢,這樣一遍一遍的劃分查詢,最後總會找到,除非你要找的數根本就沒有在這個數列中。

      說到這裡,大概就可以解釋得通為什麼二分查詢又叫折半查找了,從第一步的過程看,他就是把數列以位於中間位置的元素為界,分成左右兩半,然後根據待查元素值與當前所在陣列(注意我的用詞是當前所在陣列)的中間位置元素的大小對比情況決定下一步是在左半部子數列還是右半部子數列進行查詢。其實當我們進行到下一步查詢,即在某半部子數列進行查詢時,我們就把這一過程看做一個獨立的過程,這也是為什麼我在上面使用“當前陣列”這個詞的原因,在這一子過程中,當前陣列就是前一過程陣列的一個子陣列。說到這裡,我們到該都能嗅到了一絲遞迴的氣息~

      很多童鞋在剛接觸折半查詢時會糾結陣列中有幾個元素,陣列中元素的數量是個位數,例如有七個,數組裡面排是0~6,那很容易就知道位於中間位置的元素是3號元素;可是如果數組裡有八個元素呢?有些童鞋就會糾結了,八個元素,0~7,怎麼也看不出來有中間位置的元素啊,八個元素打對摺一邊四個嚴絲合縫啊,中間那還有元素?!寫到這裡有的同學可能會笑了,不過真的有人問過我這個問題,而且不在少數,我覺得這個問題並不可笑,其實問這些問題的童鞋是掉進了一個思維定式:所謂折半,並非一定要兩半元素數量相等啊!我對摺半的理解是找出一個相對的位置靠中間元素把原陣列劃分開,至於分的均勻不均勻就不重要了,因為這種元素個數是偶數陣列確實沒辦法均分。所以,分開就好,不用平均。對於有八個元素的陣列,在求中間位置元素的時候我們就(0+7)/2就好了,計算機算出來的會是三,那就以三號元素作為中間位置元素咯,在這裡不必糾結~

      基本的二分查詢C程式實現既可以使用迴圈,也可以使用遞迴。相信基本原理都懂,我就直接上程式碼了。

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

int mid_num(int low, int high);
int BinarySearchByLoop(int arr[], int len, int dest);
int BinarySearchByRecursion(int arr[], int dest, int low, int high);

int main(int argc, char* argv[])
{
	int array[] = {5,12,23,34,87,124,709,1024};
	int x = 0;
	int i = 0;
	int position = 0;
	int array_len = sizeof(array)/sizeof(int);
	int low = 0;
	int high = array_len - 1;
	
	printf("Please input what you want search on this array: \n");
	for(i = 0;i < array_len;++i)
	{
		if(i != (array_len-1))
			printf("%d,",array[i]);
		else
			printf("%d",array[i]);
	}
	printf("\n");

	scanf("%d",&x);
	//position = BinarySearchByLoop(array, array_len, x);
	position = BinarySearchByRecursion(array, x, low, high);
	if(position >= 0)
		printf("Your number is in the array and position %d \n",position+1);
	else
		 printf("Sorry, your number is not in the array.\n");	

	return 0;
}

int mid_num(int low, int high)
{
	return int((low + high) / 2);
}

int BinarySearchByLoop(int arr[], int len, int dest)
{
	int low = 0;
	int high = len - 1;
	int mid = mid_num(low, high);
	
	while(low <= high)
	{
		mid = mid_num(low, high);
		if(dest == arr[mid])
			return mid;
		else if(dest < arr[mid])
			high = mid - 1;
		else
			low = mid + 1;
	}
	
	return -1;
}

int BinarySearchByRecursion(int arr[], int dest, int low, int high)
{
	int mid = 0;
	if(low <= high)
	{
		mid = mid_num(low, high);
		if(dest == arr[mid])
			return mid;
		else if(dest < arr[mid])
			BinarySearchByRecursion(arr, dest, low, (mid - 1));
		else if(dest > arr[mid])
			 BinarySearchByRecursion(arr, dest, (mid + 1),high);
	}
	else
		return -1;
}
int BinarySearchByLoop(int arr[], int len, int dest)
函式是使用迴圈實現二分查詢
int BinarySearchByRecursion(int arr[], int dest, int low, int high)
函式是使用遞迴實現二分查詢
我是在ubuntu14.04下使用g++進行編譯的


執行結果如下:



如果輸入了一個數組中不存在的數:


關於二分查詢的初識就這些啦,後面還會有跟深入的學習~

相關推薦

資料結構演算法實踐 二分查詢初識

      今天起,我要對資料結構和基本的演算法進行一些簡單的複習,並在複習的基礎上對其進行深入的挖掘。這篇文章先對二分查詢進行一個簡要的複習,在之後的文章中會對其進行深入的學習。       二分查詢又叫折半查詢,是最基本的幾種查詢演算法之一。簡單的看,二分法查詢主要

資料結構演算法基礎-02-二分查詢-實踐

演算法中查詢演算法和排序演算法可謂是最重要的兩種演算法,是其他高階演算法的基礎。在此係列文章中,將逐一學習和總結這兩種基礎演算法中常見的演算法實現。首先,第一種演算法——二分(折半)查詢的學習和練習。 1、概念 二分查詢,是逐次將查詢範圍折半,縮小搜尋的範圍,直到找到那個需要的結果。

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

二分查詢 注:本題目源自《浙江大學-資料結構》課程,題目要求實現二分查詢演算法。 函式介面定義 Position BinarySearch( List L, ElementType X ); 其中List結構定義如下: typedef int Position; typ

資料結構演算法C++二分搜尋樹的刪除節點,刪除任意節點

上篇部落格介紹了怎樣刪除二分搜尋樹的最大值和最小值節點,下面介紹怎樣刪除樹的任意一個節點 上篇刪除最大值節點的操作,其實刪除的節點要麼沒有左右子節點,要麼只可能有左節點, 同樣,刪除最小值節點的操作,其實刪除的節點要麼沒有左右子節點,要麼只可能有右節點 (1)刪

資料結構演算法C++二分搜尋樹的順序性

二分搜尋樹可以查詢最小值 minimum 和最大值 maximum 可以找到一個元素的前驅(successor),後繼(predecessor),floor,和 ceil 當該元素在樹中時,前驅後繼和f

資料結構演算法二叉查詢樹 --- 第十三篇

樹是一種非線性資料結構,這種資料結構要比線性資料結構複雜的多,因此分為三篇部落格進行講解: 第一篇:樹的基本概念及常用操作的Java實現(二叉樹為例) 第二篇:二叉查詢樹 第三篇:紅黑樹 本文目錄 1、二叉查詢樹的基本概念 2、二叉查詢樹的查詢操作 3、二叉查詢樹的插

java版資料結構演算法—遞迴(二分查詢)

package com.zoujc.triangle; /** * 遞迴:二分查詢 */ class OrdArray { private int[] a; private int nElems; public OrdArray(int max){

資料結構演算法排序演算法(插入排序、希爾排序)

3、插入排序 插入排序的基本操作就是將一個數據插入到已經排好序的有序資料中,從而得到一個新的、個數加一的有序資料,演算法適用於少量資料的排序,時間複雜度為O(n^2),是穩定的排序方法。插入演算法把要排序的陣列分成兩部分:第一部分包含了這個陣列的所有元素,但將最後一個元素除外(讓陣列多一個空間才

資料結構演算法排序演算法(氣泡排序、選擇排序)

排序(Sorting) 是計算機程式設計中的一種重要操作,它的功能是將一個數據元素(或記錄)的任意序列,重新排列成一個關鍵字有序的序列。 排序演算法分類: 一、非線性時間比較類排序 1、交換排序(氣泡排序、快速排序) 2、插入排序(簡單插入排序、布林排序) 3、選擇排序(簡單選擇

資料結構演算法演算法簡介

演算法(Algorithm)是指解題方案的準確而完整的描述,是一系列解決問題的清晰指令,演算法代表著用系統的方法描述解決問題的策略機制。也就是說,能夠對一定規範的輸入,在有限時間內獲得所要求的輸出。如果一個演算法有缺陷,或不適合於某個問題,執行這個演算法將不會解決這個問題。不同的演算法可能用不同的時

資料結構演算法資料結構簡介

資料結構=資料+結構,資料結構是計算機儲存、組織資料的方式。資料結構是指相互之間存在一種或多種特定關係的資料元素的集合。通常情況下,精心選擇的資料結構可以帶來更高的執行或者儲存效率。資料結構往往同高效的檢索演算法和索引技術有關。 一、資料的邏輯結構:指反映資料元素之間的邏輯關係的資料結構,其中的

資料結構演算法連結串列—有序連結串列

2、有序連結串列 有序連結串列是在單鏈表的基礎上對單鏈表的表頭節點插入進行修改,從表頭開始根據插入值與連結串列中原先存在的資料節點進行比較判斷,若大於(或小於)該節點就向後移一個節點進行比較,直至不大於(或小於)該節點,最終實現按照從小到大(或從大到小)的順序排列連結串列。 // 插入節點,

資料結構演算法抽象資料型別(ADT)

抽象資料型別(abstract data type,ADT)是帶有一組操作的一些物件的集合。抽象資料型別是數學的抽象,只不過這種資料型別帶有自己的操作。比如表、集合、圖以及與它們各自的操作一起形成的這些物件都可以看做抽象資料型別,就像整數、實數、布林數等都是資料型別一樣。整數、實數、布林數都有各自相

資料結構演算法連結串列—雙端連結串列

2、雙端連結串列 雙端連結串列就是在單鏈表的基礎上增加一個尾節點,使連結串列既有頭節點又有尾節點,這樣方便進行連結串列尾的訪問和刪除。其計算複雜度如下:1、在表頭插入一個新的節點,時間複雜度O(1) ;2、在表尾插入一個新的節點,時間複雜度O(1) ;3、刪除表頭的節點,時間複雜度O(1) ;4

資料結構演算法連結串列—單向連結串列

連結串列(LinkedList) 連結串列是一種物理儲存單元上非連續、非順序的儲存結構,資料元素的邏輯順序是通過連結串列中的指標連結次序實現的。連結串列由一系列節點(連結串列中每一個元素稱為節點)組成,節點可以在執行時動態生成。每個節點包括兩個部分:一個是儲存資料元素的資料域,另一個是儲存下一個

資料結構演算法隨筆------二叉樹的遍歷(一文搞懂二叉樹的四種遍歷)

二叉樹的遍歷 二叉樹的遍歷(traversing binary tree)是指從根結點出發,按照某種次序依次訪問二叉樹中所有的結點,使得每個結點被訪問依次且僅被訪問一次。 遍歷分為四種,前序遍歷,中序遍歷,後序遍歷及層序遍歷 前序 中

資料結構演算法C++堆排序

首先需要介紹一下一個新的資料結構:堆 堆使用了優先佇列 普通佇列:先進先出,後進後出 優先佇列:出隊順序與入隊順序無關,與優先順序有關,一般取出優先順序最高的元素,堆入隊出隊的演算法複雜度都為O(nlogn) 最常使用的是二叉堆(Binary Heap) 如上圖所示,62稱為41和30

資料結構演算法C++三路快速排序

前兩篇部落格介紹了快速排序演算法以及對快速排序演算法的兩種改進, 下面開始介紹三路快速排序演算法,之所以稱為三路快速排序演算法,是因為其考慮了三個部分(如下圖),分別為大於 v

資料結構演算法C++快速排序(續)

上一篇部落格資料結構與演算法C++之快速排序介紹了快速排序演算法。 但是上面實現的快速排序有兩個缺點: (一)對於近乎有序的陣列,演算法的計算複雜度由O(nlogn)退化到O(n2) (二)如果陣列中存在大量重複的元素,那麼演算法的計算複雜度也會退化到O(n2) (一)對於近乎有序的

資料結構演算法C++快速排序

快速排序是一種比歸併排序還要快的排序演算法,具體原理如下圖所示 對上圖所示的陣列,首先隨機選取一個參照元素,一般選取最左邊的元素4為參照元素,然後將陣列排序成以4為分界點,左邊都是小於4的元素,右邊都是大於4的元素,按照這種方式進行不斷遞迴,就可實現整個陣列的排序。 上圖顯示的是程式