分治法是算法设计方法的一种,它通过将问题划分为规模更小的子问题,递归的解决划分后的子问题,再将结果合并从而高效的解决问题。下面通过简单的寻找数组中最大最小值问题,认识到分治思想的优秀之处。
对于寻找数组中最大最小值问题,简单的扫描,需要两遍确定min,max,即复杂度为2*N
奇偶位排序: 经历N/2 次比较,讲较大的数放到奇数位子,较小数放到偶数位置,最后通过N次比较获取min以及max;
int evenfind(int *array, int count)
{
if(array == NULL)
return -1;
for(int i =0; i< count; i+=2)
{
//replace,so the bigger put first
if(array[i] > array[i+1])
{
int temp = array[i+1];
array[i+1] = array[i];
array[i] = temp;
}
}
int max =0;
for(int i=1; i<count; i+=2)
{
if(max < array[i])
max = array[i];
}
return max;
}
折半查找:分别求出前后N/2个数的min 和 max,然后取较小的min,较大的为max。递归执行过程,先走到可以分的最左边,然后往右边,这样一个最小单元left+right走完,往left+right 的右边拥有同样大小部分,这时把到该部分分为left ,right,完成left+right。依次循环。
比如1,2,3,45,6,7,8 第一次分为 left 1234,right 5,6,7,8. 第二次分为left 1,2 right 3,4; 第三次分为left 1,right 2;
不可分,比较得到返回2,在比较 left 3,right4,返回4, 再比较left 2和 right 4,返回4,;
然后依次比较5,6返回6,比较7,8返回8;
最后比较4和8 返回8;
int search(int *array, int begin , int end)
{
if(end - begin <=1)
{
if(array[end] < array[begin])
return array[begin];
else
return array[end];
}
int maxLeft=0, maxRight=0;
maxLeft = search(array, begin, begin + (end - begin) /2); //一直分到最左边,return max
maxRight = search(array,begin + (end - begin)/2, end); //然后走右边,return max
if(maxLeft > maxRight)
return maxLeft;
else
{
return maxRight;
}
}
关于折半查找复杂度分析如下。
快速排序:快速排序使用了分治的思想,最坏情况下复杂度为 N*N, 但是平均性能非常好,期望时间复杂度是 n*logn(即对原数列每次分开后形成类似完全二叉树,层数为logn,而每层的比较次数均为n,故为n*logn),另外还可以原址排序。
bool QuickSort(int *array,int begin, int end)
{
if(begin < end)
{
//取第一个数据出来,作为比较对照
int temp = array[begin];
int i = begin;
int j = end;
while(i < j)
{
while(i < j && array[j]> temp) //从尾往前找到第一个大于的值
j--;
if(i<j)
{
array[i] = array[j]; //把这个值放到之前已经被取出来值的地方i,在j处形成空缺
i++;
}
while (i<j && array[i]< temp) //顺序找到第一个小于参考值
i++;
if(i<j)
{
array[j] = array[i]; //把这个值填到前面形成空缺处 j,i处继续形成空缺
j--;
}
}
array[i] = temp; //循环过后,紧接前面i处空缺,填上最开始的参照值
int l = i;
//http://blog.csdn.net/morewindows/article/details/6684558
QuickSort(array,begin, l-1);
QuickSort(array, l+1, end);
return true;
}
else
{
return false;
}
}
桶排序:桶排序是复杂度 为N,或接近N 排序算法,适合数据分布均匀的排序;思想是分配适当个数的桶,再桶中对数据进行插入排序。桶排序并不是分治思想的应用,但是这种把数据按基数分放到桶中,对桶中数据插入排序,也是分开处理吧。
void doinsertionsortforbucket(int* input, int len)
{
while( len-- > 0) {
if (input[len] > input[len+1]) {
int tmp = input[len];
input[len] = input[len+1];
input[len+1] = tmp;
} else
return;
}
}
void bucketsort(int* input)
{
queue<int> *buckets[BUCKET_K];
for ( int i = 0; i < BUCKET_K; i++ )
buckets[i] = new queue<int>;
// Hash the input and insert the content into appropriate bucket based on hash.
for (int i=0;i<INPUT_SIZE;i++)
{
int hashValue = Hash(input[i]);
if (hashValue >= BUCKET_K)
hashValue = BUCKET_K-1;
buckets[hashValue]->push(input[i]);
}
// extract the content from each of the buckets in order.
// using insertion sort
int outputidx = 0;
for ( int i = 0; i < BUCKET_K; i++ )
{
if (buckets[i]->size() == 1) {
input[outputidx++] = buckets[i]->front();
cout << buckets[i]->front() << " | ";
buckets[i]->pop();
}
if (buckets[i]->size() > 1)
{
while (!buckets[i]->empty())
{
input[outputidx] = buckets[i]->front();
doinsertionsortforbucket(input, outputidx);
cout << buckets[i]->front() << " ";
buckets[i]->pop();
outputidx++;
}
cout << "| ";
}
}
// clear buckets.
for ( int i = 0; i < BUCKET_K; i++ )
delete buckets[i];
}
总结: 分治思想应用了排序的位置信息,形成线性或树形结构,分开进行比较,不用每次都从头到尾重复某些比较,达到优化时间复杂度的目的。
参考
www.geeksforgeeks.org/bucket-sort-2/
www.sourcetricks.com/2013/03/bucket-sort.html#.VdnXmfmqpBc
blog.sina.com.cn/s/blog_614316190100ei83.html
blog.csdn.net/morewindows/article/details/6684558