您的位置:首页 > 职场人生

二分查找、快速排序对比和详解

2016-03-24 22:19 681 查看
这两个都是用到分治的思想很容易搞混。而且即使binarySearch是用到分治也不一定意味着一定要用递归去实现,可以通过循环实现。二分查找和快速排序属于面试笔试的高频问题有必要总结一下。

由于循环相比递归少了很多内存分配和压栈的操作开销会少很多,所以binarySearch最好的实现方式是通过循环实现。binarySearch有一个大前提是数组是有序的,接下来没什么好解释的直接代码:

int binarySearch(int *a,int l,int r,int number)
{
int mid = (l+r)/2;

while(l<=r){

if(a[mid]<number)
l = mid+1;
else if(a[mid]>number)
r = mid-1;
else  if(a[mid] == number )
return mid;

mid = (r+l)/2;
}
return -1;
}


快速排序主要思想也是分治,在升序(降序)排序的过程中:

两个指针分别从数组头和尾部向中间遍历,当尾部指针遇到比枢纽小(大)的值,头部指针遇到比枢纽大(小),交换两个指针所指向的值的位置。

这里涉及到两个比较关键容易混淆的问题:

1.枢纽的选取。

2.停止条件的设置。

3.当头尾指针交叉后,枢纽和哪个指针进行交换。



如图所示当划分完毕后,在枢纽左边的应该是都比枢纽小(大);在枢纽右边的应该都比枢纽大(小),总之他们相对于枢纽来说是相对有序的。所以最后枢纽所在的位置很关键。

枢纽的初始位置选择有两种最简单的方法:选头部和选尾部

以下的解释统一以升序为例子

枢纽的初始位置选择有两种最简单的方法:选头部和选尾部。

这时候划分完毕之后交换的方案也有两种主要根据枢纽的选择位置来决定。

(1)如果枢纽选的是头部,那么划分完毕后要和尾指针进行位置交换。因为要求交换完成后,枢纽左边的都是小于枢纽的数,而此时在不越界的情况下尾指针所指位置是刚好小于枢纽

(2)如果枢纽选的是尾部的指针,则划分完毕后要和头指针进行交换。因为此时头指针所指的位置恰好大于枢纽,因为在不越界的情况下枢纽元右侧的均要大于枢纽元

停止条件:

停止条件的设置不要在循环判断体中设置,要在循环体内设置。理论上来讲每一次比对的停止条件都是头指针大于枢纽元素,尾指针指向小于枢纽元素。即使最后一次也不例外,因为要找分界点方便交换枢纽。

所以代码:

void myQuickSort(int *a,int left,int right)
{
if(left>=right)
return;
int l = left, r = right;
int pivot = left;//枢纽元选择的是头部

for(;;)
{

while(*(a+l) <= *(a+pivot)&& l<right)//防止越界
l++;
while(*(a+r) >= *(a+pivot)&& r>L)//防止越界
r--;
if(l<r)
myswap(a,l,r);
else
break;//如果属于指针位置交叉的情况则停止
}

if(*(a+pivot)<*(a+r))            //如果此时尾指针指向的元素刚好大于枢纽元素
myswap(a,pivot,r);//枢纽和尾指针进行交换使得枢纽元右侧的元素全部大于枢纽元,

myQuickSort(a,left,r-1);
myQuickSort(a,r+1,right);

}

选尾部作枢纽:
void myQuickSort(int *a,int left,int right)
{
if(left>=right)
return;
int l = left, r = right;
int pivot = right;//枢纽元选的尾部
for(;;)
{

while(*(a+l) <= *(a+pivot))
l++;
while(*(a+r) >= *(a+pivot))
r--;
if(l<r)
myswap(a,l,r);
else
break;
}

if(*(a+l) > *(a+pivot))
myswap(a,pivot,l);//和头指针交换
myQuickSort(a,left,l-1);//不包含pivot
myQuickSort(a,l+1,right);//不包含pivot
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息