有序顺序表的最少时间查找

一 概述

在有序递增顺序表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;
}

折半查找的结果:

  

四 顺序查找与折半查找的特点

顺序查找的优点:对于表结构无任何要求,既适用于顺序结构,也适用于链式结构,无论记录是否按关键字有序均可应用。

顺序查找的缺点:平均查找长度较大,查找效率较低,所以当表长很大的时候,不适合使用顺序查找

折半查找的优点:折半查找的次数比较少,查询效率高。

折半查找的缺点:折半查找对表结构要求比较高,只能用于顺序存储的有序表,查找前需要排序,而排序本身是一种费时的运算。同时为了保持顺序表的有序性,对有序表进行插入和删除时,平均比较和移动表中一半元素,同样比较费时,故折半查找不适合数据元素经常变动的线性表

猜你喜欢

转载自blog.csdn.net/calm_encode/article/details/106984552