折半查找插入排序法

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

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

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

例如: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~

posted @ 2011-11-19 20:39  java简单例子  阅读(1650)  评论(0编辑  收藏  举报