有序順序表的最少時間查找

一 概述

在有序遞增順序表L中,使用最少的時間查找數值爲x的元素,若找到則將其與後繼元素位置交換,若找不到則將其插入表中並使表中並使表中的元素仍然遞增有序。

二 算法思想

對於有序遞增順序表的查找問題,我們可以採用順序查找,也可以使用折半查找。顯然後者比前者效率高,所以使用折半查找會比較快。

三 代碼實現

順序查找:從表的一端開始,依次將記錄的關鍵字和給定的值進行比較,若某個記錄的關鍵字和給定的值相等,則查找成功;反之,若掃描整個表後,仍未找到關鍵字和給定值相等的記錄,則查找失敗。順序查找方法既適用於線性表的順序存儲結構,又使用於線性表的鏈式存儲結構。

#include<iostream>//輸入頭 
using namespace std;//標準輸入輸出

typedef int Status;
typedef int ElemType;

#define MAXSIZE 100
#define ERROR -1
#define OK 0

typedef struct {
	ElemType *elem;
	int length;
}SqList; 

Status init_Queue(SqList &L){
	
	L.elem = new ElemType[MAXSIZE]; //初始化最大長度的順序表 
	
	if(!L.elem){
		return ERROR; //初始化失敗 
	}
	
	L.length = 0; //初始時數據表爲空 
	return OK;
}

Status FindAndSwop_Queue(SqList &L,ElemType x) {
	
	ElemType temp;
	int i=0,j=0;

	while(i<L.length) {
		if(L.elem[i]==x && i != L.length -1) {
			temp = L.elem[i];
			L.elem[i] = L.elem[i+1];
			L.elem[i+1] = temp;
			break;
		}
		
		if(x > L.elem[L.length-1]){
			L.elem[L.length] = x;
			L.length++;
		}else if(L.elem[i] < x && x < L.elem[i+1]){
			for(j = L.length - 1; j >= i+1; j--){
				L.elem[j+1] = L.elem[j];
			}
			++L.length;
			L.elem[i+1] = x;
			break; 
		}
		i++;
	}

	return OK;
}

int main(){
	SqList L;
	ElemType x;
	 
	cout<<"1.初始化順序表!\n";
	cout<<"2.輸入6個不同的數字!\n";
	cout<<"3.查詢x並且保持有序的序列!\n";
	cout<<"0.退出!"<<endl<<endl;
	
	int elect = -1;
	
	while(elect !=0){
		cout<<"請選擇你的後續操作:"; 
		cin>>elect;
		switch(elect){
			case 1:
				if(!init_Queue(L)){
					cout<<"初始化順序表成功!"<<endl; 
				}else{
					cout<<"初始化順序表失敗!"<<endl; 
				}
				break;
			case 2:
				cout<<"請輸入6不同數字:" ;
				for(int i = 0; i < 6; i++){
					cin>>L.elem[i];
					L.length = 6; 
				}
				break;
			case 3:
				cout<<"請輸入要查找的數字:"; 
				cin>>x; 
				FindAndSwop_Queue(L,x);
				cout<<"查詢x並且保持有序的序列爲:" ;
				for(int i = 0; i < L.length; i++ ){
				 cout<<L.elem[i]<<" ";
				} 
				cout<<endl; 
				break;
		}
	}
	return 0;
}

順序查找的結果:

  

折半查找(二分查找):折半查找是一種效率比較高的查找方法,但是,折半查找要求線性表必須採用順序存儲結構,而且表中的元素按關鍵字有序排序。該算法已經定義了遞增,所以在折半查找的過程中,從表中間記錄開始,如果給定值和中間記錄關鍵字相等,則查找成功;如果給定值大於或者小於中間記錄的關鍵字,則在表中大於或者小於中間記錄的那一半中查找,這樣重複操作,直到查找成功,或者在某一步中查找區間爲空,則代表查找失敗。

折半查找每一次查找比較都使查找範圍縮小一半,與順序查找相比,很顯然會提高查找效率。爲了標記查找過程中每一次的查找區間,我們可以定義low和high來表示當前查找區間的下界和上界,mid爲區間的中間位置。

/*
折半查找的步驟:
1.設置查找區間初值,low爲1,high爲表長度
2.當low小於high時,循環執行一下操作:
    。min取值爲low和high的中間值;
    。將給定值key與中間位置記錄的關鍵字進行比較,若相等則查找成功,返回中間位置mid;
    。若不相等則利用中間位置記錄將表對分成前,後兩個子表。如果key比中間位置記錄的關鍵字
      小,則high重新取值爲mid-1,否則low重新取值爲mid+1;
3.循環結束,說明查找區間爲空,則查找失敗,返回0;
*/
#include<iostream>//輸入頭 
using namespace std;//標準輸入輸出

typedef int Status;
typedef int ElemType;

#define MAXSIZE 100
#define ERROR -1
#define OK 0

typedef struct {
	ElemType *elem;
	int length;
}SqList; 

Status init_Queue(SqList &L){
	
	L.elem = new ElemType[MAXSIZE]; //初始化最大長度的順序表 
	
	if(!L.elem){
		return ERROR; //初始化失敗 
	}
	
	L.length = 0; //初始時數據表爲空 
	return OK;
}

Status FindAndSwop_Queue(SqList &L,ElemType x) {
	
	ElemType temp;
	int low = 0, high = L.length-1, mid,i;

	while(low <= high) {
		//在循環體中初始化mid值,是爲了在動態變化中mid值也會動態變化。 
		mid = (low+high)/2;
		//mid < L.length表示若是最後一個元素與x相等,則不存在與其後繼交換的操作。 
		if(L.elem[mid] == x && mid < L.length - 1){
			temp = L.elem[mid];
			L.elem[mid] = L.elem[mid+1];
			L.elem[mid+1] = temp;
			break; 
		}else if(L.elem[mid] < x) {
			low = mid + 1;
		}else{
			high = mid -1;
		}
	}
	
	if(low > high){
		//當high<low的時候,說明查找區間不存在,也即沒有關鍵字爲x的元素,此時選擇插入值爲x的元素 
		//於此同時可得,關鍵字爲x的元素值屬於區間L.elem[high]<x<L.elem[low]; 
		for(i = L.length - 1; i > high ; i--) { 
			L.elem[i+1] = L.elem[i];
		}
			++L.length;
			L.elem[i+1] = x;
	} 
	return OK;
}

int main(){
	SqList L;
	ElemType x;
	 
	cout<<"1.初始化順序表!\n";
	cout<<"2.輸入6個不同的數字!\n";
	cout<<"3.查詢x並且保持有序的序列!\n";
	cout<<"0.退出!"<<endl<<endl;
	
	int elect = -1;
	
	while(elect !=0){
		cout<<"請選擇你的後續操作:"; 
		cin>>elect;
		switch(elect){
			case 1:
				if(!init_Queue(L)){
					cout<<"初始化順序表成功!"<<endl; 
				}else{
					cout<<"初始化順序表失敗!"<<endl; 
				}
				break;
			case 2:
				cout<<"請輸入6不同數字:" ;
				for(int i = 0; i < 6; i++){
					cin>>L.elem[i];
					L.length = 6; 
				}
				break;
			case 3:
				cout<<"請輸入要查找的數字:"; 
				cin>>x; 
				FindAndSwop_Queue(L,x);
				cout<<"查詢x並且保持有序的序列爲:" ;
				for(int i = 0; i < L.length; i++ ){
				 cout<<L.elem[i]<<" ";
				} 
				cout<<endl; 
				break;
		}
	}
	return 0;
}

折半查找的結果:

  

四 順序查找與折半查找的特點

順序查找的優點:對於表結構無任何要求,既適用於順序結構,也適用於鏈式結構,無論記錄是否按關鍵字有序均可應用。

順序查找的缺點:平均查找長度較大,查找效率較低,所以當表長很大的時候,不適合使用順序查找

折半查找的優點:折半查找的次數比較少,查詢效率高。

折半查找的缺點:折半查找對錶結構要求比較高,只能用於順序存儲的有序表,查找前需要排序,而排序本身是一種費時的運算。同時爲了保持順序表的有序性,對有序表進行插入和刪除時,平均比較和移動表中一半元素,同樣比較費時,故折半查找不適合數據元素經常變動的線性表

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章