一 概述
在有序遞增順序表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;
}
折半查找的結果:
四 順序查找與折半查找的特點
順序查找的優點:對於表結構無任何要求,既適用於順序結構,也適用於鏈式結構,無論記錄是否按關鍵字有序均可應用。
順序查找的缺點:平均查找長度較大,查找效率較低,所以當表長很大的時候,不適合使用順序查找。
折半查找的優點:折半查找的次數比較少,查詢效率高。
折半查找的缺點:折半查找對錶結構要求比較高,只能用於順序存儲的有序表,查找前需要排序,而排序本身是一種費時的運算。同時爲了保持順序表的有序性,對有序表進行插入和刪除時,平均比較和移動表中一半元素,同樣比較費時,故折半查找不適合數據元素經常變動的線性表。