【查找算法】——順序查找、折半查找、分塊查找(索引查找)

轉載出處:http://www.cnblogs.com/kunhu/p/3634562.html


查找算法


概述:

查找算法:就是在是數據元素集合中查看是否存在於指定的關鍵字相等的元素。html

查找分爲兩種:靜態查找動態查找ios

1) 靜態查找:是指在數據元素集合中查找與給定的關鍵字相等的元素。算法

2) 動態查找:就是指在查找過程當中,若是數據元素集合中不存在與給定的關鍵字相等的元素,則將該元素插入到數據元素集合中。函數


靜態查找主要包括順序表、有序順序表和索引順序表的查找。spa

1) 順序表的查找,就是指從表的第一個元素與給定關鍵字比較,直到表的最後。指針

2) 有序順序表的查找,在查找的過程當中若是給定的關鍵字大於表的元素,就能夠中止查找,說明表中不存在該元素(假設表中的元素按照關鍵字從小到大排列,而且查找從第一個元素開始比較)code

3) 索引順序表的查找是爲主表創建一個索引,根據索引肯定元素所在的範圍,這樣能夠有效地提升查找的效率。orm

 

動態查找主要包括二叉排序樹平衡二叉樹B-樹B+樹htm

這些都是利用二叉樹和樹的特色對數據元素集合進行排序,經過將元素插入到二叉樹或樹中創建二叉樹或樹,而後經過對二叉樹或樹的遍歷按照從小到大輸出元素的序列。對象

 

散列表是利用散列函數的映射關係直接肯定要查找元素的位置,大大減小了與元素的關鍵字的比較次數。

創建散列表的方法主要有直接定址法平方取中法摺疊法除留餘數法(最經常使用)等。

可是會存在衝突,解決衝突的最爲經常使用的方法主要有兩個:開放定址法鏈地址法

 

一.靜態查找

1.順序表的查找——順序查找

順序查找(Sequential Search)又稱爲線性查找,是一種最簡單的查找方法。
 

        從表的一端開始,向另外一端逐個按要查找的值key 與關鍵碼key進行比較,若找到,查找成功,並給出數據元素在表中的位置;若整個表檢測完,仍未找到與關鍵碼相同的key值,則查找失敗,給出失敗信息。

說白了就是,從頭至尾,一個一個地比,找着相同的就成功,找不到就失敗。很明顯的缺點就是查找效率低。


【適用性】:適用於線性表的順序存儲結構和鏈式存儲結構。

 平均查找長度=(n+1)/2.

【順序查找優缺點】:

缺點:是當n 很大時,平均查找長度較大,效率低;

優勢:是對錶中數據元素的存儲沒有要求。另外,對於線性鏈表,只能進行順序查找。

#include<iostream>
using namespace std;

#define MAX 11

typedef int key_type;

typedef struct element
{
	key_type key;   //關鍵字 
}elem;

int seq_search(elem e[], key_type key, int n)
{
	int i = 0;
	while(i < n && e[i].key != key)
	{
		i++;
	}
	
	if(i < n)
		return i;
	else 
		return -1;
}
 
 int main(int argc, char** argv)
 {
 	elem linelist[MAX] = {1,5,9,7,12,11,10,8,6,2,3};
 	int n = 11;
 	int i = 0;
 	key_type key = 8;
 	printf("線性表中的元素爲: \n");
 	
 	while(i < n)
 	{
		printf("%d\n",linelist[i].key);
		i++; 
	}	
	
	printf("\n關鍵字[%d]在線性表中的位置下標爲[%d]\n", key, seq_search(linelist, key, n));
	
	getchar();
	system("pause");
 }


2.有序順序表的查找——折半查找

        在有序表中,取中間元素做爲比較對象,若給定值與中間元素的關鍵碼key相等,則查找成功;若給定值小於中間元素的關鍵碼,則在中間元素的左半區繼續查找;若給定值大於中間元素的關鍵碼,則在中間元素的右半區繼續查找。不斷重複上述查找過程,直到查找成功,或所查找的區域無數據元素,查找失敗。

【步驟】
① low=0;high=length-1;                                                          // 設置初始區間
② 當low>high 時,返回查找失敗信息                                         // 表空,查找失敗
③ 當low<=high,mid=(low+high)/2;                                           //肯定該區間的中點位置
      a. 若key < elem[mid].key,high = mid-1;轉②                    // 查找在左半區進行
      b. 若key > elem[mid].key,low  = mid+1; 轉②                  // 查找在右半區進行
      c. 若key = elem[mid].key,返回數據元素在表中位置        // 查找成功

 

有序表按關鍵碼排列以下:

3,  5,  6,  8,  9,  12,  17,  23,  30,  35,  39,  42

在表中查找關鍵碼爲9的數據元素:

#include<iostream>
using namespace std;

#define MAX 12

typedef int key_type;

typedef struct element
{
	key_type key;   //關鍵字 
}elem;


int binary_search(elem e[], key_type key, int n)
{
	int low = 0, high = n - 1;
	int mid;
	
	while(low <= high)
	{
		mid = (low + high)/2;
		
		if(e[mid].key == key)
			return mid;
		else if(key < e[mid].key)
			high = mid - 1;
		     else
			low = mid + 1;
	}
	
	return -1; //沒找到 	
}

 
 int main(int argc, char** argv)
 {
 	elem linelist[MAX] = {3,5,6,8,9,12,17,23,30,35,39,42};
 	int n = 12;
 	int i = 0;
 	key_type key = 9;
 	printf("線性表中的元素爲: \n");
 	
 	while(i < n)
 	{
		printf("%d\n",linelist[i].key);
		i++; 
	}	
	
	printf("\n關鍵字[%d]在線性表中的位置下標爲[%d]\n", key, binary_search(linelist, key, n));
	
	getchar();
	system("pause");
 }

折半查找算法的平均查找長度爲O(logn),與順序查找方法相比,折半查找算法的效率高。速度比順序查找快。
但折半查找只能使用於有序表,須要對n個元素預先進行排序(僅限於順序存儲結構,對於線性鏈表沒法進行折半查找)。
 

3.分塊查找(索引查找)

分塊查找又稱索引順序查找,是對順序查找的一種改進。分塊查找要求將查找表分紅 若干個子表,並對子表創建索引表,查找表的每個子表由索引表中的索引項肯定。索引項包括兩個字段:關鍵碼字段(存放對應子表中的最大關鍵碼值) ;指針字段(存放指向對 應子表的指針) ,而且要求索引項按關鍵碼字段有序。查找時,先用給定值key 在索引表中 檢測索引項,以肯定所要進行的查找在查找表中的查找分塊(因爲索引項按關鍵碼字段有序,可用順序查找或折半查找) ,而後,再對該分塊進行順序查找。


如關鍵碼集合爲:

                           (8, 20, 13, 17, 40, 42, 45, 32, 49, 58, 50, 52, 67, 79, 78, 80)

按關鍵碼值20,45,58, 80分爲四塊創建索引表。

                              

分塊查找的函數分爲以下兩步:
a)首先肯定待查找的結點屬於哪一塊,即查找所在的塊;
b)而後,在塊內查找要查的結點。

設表共n個結點,分b塊,s=n/b

(分塊查找索引表)平均查找長度=Log2n/s+1+s/2

(順序查找索引表)平均查找長度=(S2+2S+n)/(2S)

#include<iostream>
using namespace std;

#define MAX 16

typedef int key_type;

struct elem
{
	key_type key; //關鍵字 
};

//索引結構 
struct index         
{
	key_type key; //索引值 
	long low;     //起始位置 
	long high;    //終止位置 
};

int index_search(elem e[], key_type key, int n, index idx[], int idx_length)
{
	int low = 0;
	int high = idx_length - 1;
	int mid;
	
	//採用折半查找在索引表裏找到關鍵字所在的塊
	while(low <= high)
	{
		mid = (low + high)/2;
		if(key < idx[mid].key)
			high = mid - 1;
		else if(key > idx[mid].key)
			low = mid + 1;
		     else
			break;
	} 
	
	//採用順序查找的方法從塊中查找關鍵值
	int i = idx[mid].low;
	
	while(i <= idx[mid].high && e[i].key != key)
	{
		i++;
	} 
	
	if(i > idx[mid].high)
		return -1;
	else
		return i;
}


int main(int argc, char** argv)
{
	elem linelist[MAX] = {
		8, 20, 13, 17,
		40, 42, 45, 32,
		49, 58, 50, 52,
		67, 79, 78, 80
	};
	
	int n = sizeof(linelist) / sizeof(elem);
	key_type key = 50;
	
	//創建索引表
	index index_table[4] = {{20,0,3}, {45,4,7}, {58,8,11}, {80,12,15}}; 
	int idx_length = sizeof(index_table) / sizeof(index);
	
	printf("線性表中的元素爲:\n");

	int i = 0;
	
	while(i < n) 
	{
		printf("%d\n",linelist[i].key);
		i++;
	}
	
	printf("\n關鍵字[%d]在線性表中的位置下標爲[%d]", key, index_search(linelist, key, n, index_table, idx_length));
	
	getchar();
	system("pause");
}