有序和无序数组的二分搜索算法+select第k小的元素

题目意思

1、给定有序数组A和关键字key,判断A中是否存在key,如果存在则返回下标值,不存在则返回-1。

2、给定无序数组A和关键字key,判断A中是否存在key,如果存在则返回1,不存在则返回0。

3、给定无序数组A和下标k,找到A[k]并输出,渐进时间O(n),基于快排的划分函数的二分思想。

对于1、2问题,我们都可以简单的写出O(n)的从头到尾为的扫描算法,这里就不在累赘,这里我们讨论的是基于二分查找的算法,使其时间在渐进意义上达到O(logn)。

对于有序的数组,很“容易”写出基于二分的函数、

那么问题2,对于无序数组,怎么查找呢?这里我们用到了快速排序的划分原则。算法大致如下:

函数调用BinarySearch(a,n,key); a[1..n]

在无序数组a[n]中查找x是否存在,如果存在返回1,不存在返回0

这里我们用到快速排序中的划分规则,大致意思如下

将数组A[p..r]划分为两个字数组A[p..q-1]和A[q+1..r],使得

A[p..q-1]中的每个元素都小于等于A[q],并且,小于等于A[q+1..r]

对于查找关键字key,if(key==A[q]) return 1;

if(key<A[q])查找字数组A[p..q-1]

if(key>A[q])查找字数组A[q+1..r]


代码和注释:


<span style="font-size:18px;">/**
  *@xiaoran
  */
#include<iostream>
#include<cstdio>
#include<map>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<vector>
#include<stack>
#include<cstdlib>
#include<cctype>
#include<cmath>
#define LL long long
using namespace std;

/**
 *二分查找
 *函数调用BinarySearch(a,0,n-1,key);
 *在有序数组a[n]中查找x是否存在,如果存在返回下标,不存在返回-1
 */
int BinarySearch(int *a,int left,int right,int &key){
    //在有序数组a[n]中查找x是否存在,如果存在返回下标,不存在返回-1
    while(left<=right){
        int mid=(left+right)/2;
        if(key==a[mid]) return mid;
        else if(key>a[mid]) left=mid+1;
        else right=mid-1;
    }
    return -1;
}

/**
 *二分查找
 *函数调用BinarySearch(a,n,key);
 *在无序数组a[n]中查找x是否存在,如果存在返回1,不存在返回0
 *这里我们用到快速排序中的划分规则,大致意思如下
 *将数组A[p..r]划分为两个字数组A[p..q-1]和A[q+1..r],使得
 *A[p..q-1]中的每个元素都小于等于A[q],并且,小于等于A[q+1..r]
 *对于查找关键字key,if(key==A[q]) return 1;
 *if(key<A[q]) 查找字数组A[p..q-1]
 *if(key>A[q]) 查找字数组A[q+1..r]
 */

int Binary_Init(int *a,int p,int r){
    int tmp,i,j;
    tmp=a[p];
    i=p+1; j=r;
    while(true){
        while(a[i]<=tmp) ++i;
        while(a[j]>tmp) --j;
        if(j<=i) break;
        else{
            swap(a[i],a[j]);
            ++i; --j;
        }
    }
    swap(a[p],a[j]);//关键字放到中间
    return j;//返回关键字的位置
}

int BinarySearchPlus(int *a,int l,int r,int key){
    if(l<r){
        int mid=Binary_Init(a,l,r);
        //cout<<a[mid]<<" "<<key<<endl;
        if(a[mid]==key) return 1;//Yes
        else if(key<a[mid]){//搜索左边一半
            return BinarySearchPlus(a,l,mid-1,key);
        }
        else{//key>a[mid],//搜索右边一半
            return BinarySearchPlus(a,mid+1,r,key);
        }
    }
    if(l==r) return a[l]==key;//只有一个元素
    return 0;//No
}


/**
 *无序数组中的select(A,p,r,k)选择数组中的第k小的元素
 */
int Partition(int *A,int p,int r){
    int i,j,x;
    i=p+1; j=r;
    x=A[p];
    while(true){
        while(A[i]<=A[p]) ++i;
        while(A[j]>A[p]) --j;

        if(j<=i) break;
        else{
            swap(A[i],A[j]);//交换两个违反规则的值
            ++i; --j;
        }
    }
    swap(A[p],A[j]);
    return j;
}

/**
 *给出一个无序的数组,在渐进时间O(n)的情况下,
 *选出第k小的元素的值
 */
int Select_k(int *A,int p,int r,int k){
    if(k<1||k>r) return -1;

    int index;
    if(p==r) return A[p];
    int q=Partition(A,p,r);
    index=q-p+1;//找到的是第几个值
    //cout<<index<<endl;
    if(index==k){
        return A[q];
    }
    else if(index<k){//此时向右查找
        return Select_k(A,q+1,r,k-index);//查找的是相对位置的值,k在右段中的下标为k-index
    }
    else{
        return Select_k(A,p,q-1,k);
    }
}




int main()
{
    int A[9]={0,9,4,3,12,5,34,55,44};
    int key;
    while(cin>>key){
        cout<<BinarySearch(A,1,8,key)<<endl;

        cout<<BinarySearchPlus(A,1,8,key)<<endl;
    }


	return 0;
}

</span>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值