折半查找插入排序法

我们知道折半查找只能在有序的数组里才能使用。

其实在插入排序过程中,大家细心的话会发现,每次找插入位置时,这段元素是有序的,那么在这里为使用折半查找提供了条件。

 但是用传统的折半查找肯定不行,因为我们这里要找的是要插入的位置

例如:42,53, 64, 85, 58这5个元素在插入排序里就是58前面的元素全部有序,我们要找的是58应该插入的位置,应该是在64所在的位置

而这个64所在的位置就是我们折半查找要查找的位置,其实就是53<58<64,在这里我对折半查找稍作改进

int binsearch(int *A,int first,int last,int x)
{
	int mid=0;
	int a=0;
	while(first>=0&&last>=0&&(last-first)>1)
	{
		mid=(first+last)/2;
		a=COMPARE(A[mid],x);
		switch(a)
		{
		case 1:		last=mid;    break;                  //在这里对折半查找稍作改动last=mid-1;改为last=mid;
		case 0:		return mid;    break;
		case -1:	first=mid;   break;                  //这里也对折半查找稍作改动
		}
	}
	mid=(first+last)/2;
	if((COMPARE(A[mid],x)==1)&&mid==0)                   //当插入位置w为A[0]时,要另外讨论
		return 0;
	else                                                 
		return last;
}


首先last=mid-1;改为last=mid;     first=mid+1;也改为了first=mid;循环退出条件改为while(first>=0&&last>=0&&(last-first)>1)

如此一来,我们最终总会得到上面示例中first位于53所在的位置,last位于64所在的位置,一般情况下我们只要返回last就够了

但有一种情况要注意,就是当要查找的位置位于元素最前面,例如:42,56,78,98,31

如果按照上述方法,first位于42所在的位置,last位于56所在的位置,如果此时返回last肯定是不对的。

所以对于这种情况,要另外讨论mid=(first+last)/2;  if((COMPARE(A[mid],x)==1)&&mid==0)    return 0;

再一次取mid,如果mid==0;说明first位于42所在的位置,last位于56所在的位置,而且if(COMPARE(A[mid],x)==1),如果A[mid]>x,即42>31,那么这时该插入的位置应该位于A[0]

以下是折半插入排序部分代码:

void Insertionsort2(int *A,int n)
{
	int i=0;
	int j=0;
	int v=0;
	
	for(i=1;i<n;i++)                  //i从1~n-1递增
	{
		v=A[i];
		if(A[i-1]>v)
		{
			j=binsearch(A,0,i-1,v);   //用折半查找找到要插入的位置
			for(;i>j;i--)
			{
				A[i]=A[i-1];
			}
			A[j]=v;
		}
	}
}


下面是我的测试代码,已测试过

//折半插入排序Insertsort2()
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define COMPARE(x,y)  (((x)>(y))?1:(((x)==(y))?0:-1))

void print(int *A,int n);
void Insertionsort2(int *A,int n);
int binsearch(int *A,int first,int last,int x);

void main()
{
	int n=0;
	int i=0;            //循环变量
	int *A=NULL;

	printf("你想要多少个随机数?  ");
	scanf("%d",&n);
	if(n<1)
		n=1;

	A=(int*)malloc(n*sizeof(int));
	if(A==NULL)
	{
		printf("Out of memory!\n");
		exit(1);
	}

	srand(time(NULL));                         //产生0~999之间的n个随机数
	for(i=0;i<n;i++)
	{
		A[i]=rand()%1000;
	}

	printf("\n");
	printf("Before sorting!\n");
	print(A,n);
	printf("After sorted!\n");
	Insertionsort2(A,n);
	print(A,n);
}

void Insertionsort2(int *A,int n)
{
	int i=0;
	int j=0;
	int v=0;
	
	for(i=1;i<n;i++)                  //i从1~n-1递增
	{
		v=A[i];
		if(A[i-1]>v)
		{
			j=binsearch(A,0,i-1,v);   //用折半查找找到要插入的位置
			for(;i>j;i--)
			{
				A[i]=A[i-1];
			}
			A[j]=v;
		}
	}
}
		


void print(int *A,int n)
{
	int i=0;
	for(i=0;i<n;i++)
	{
		if(i%8==0)
			printf("\n");
		printf("%3d  ",A[i]);
	}
	printf("\n");
}

int binsearch(int *A,int first,int last,int x)
{
	int mid=0;
	int a=0;
	while(first>=0&&last>=0&&(last-first)>1)
	{
		mid=(first+last)/2;
		a=COMPARE(A[mid],x);
		switch(a)
		{
		case 1:		last=mid;    break;                  //在这里对折半查找稍作改动last=mid-1;改为last=mid;
		case 0:		return mid;    break;
		case -1:	first=mid;   break;                  //这里也对折半查找稍作改动
		}
	}
	mid=(first+last)/2;
	if((COMPARE(A[mid],x)==1)&&mid==0)                   //当插入位置w为A[0]时,要另外讨论
		return 0;
	else                                                 
		return last;
}


对于算法方面的问题,确实不容易想,为这个问题我也苦恼了很长时间,发了帖子也没有有价值的回复,甚至有人嘲讽你,但我最终还是做出来了

这个算法可能不是很好,但是这真是我自己想出来的,完全原创。

大家有什么别的思路完全可以交流交流,呵呵O(∩_∩)O~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值