Model+Collection+%98O%C6%B7%C3%C0%C5%AE%D6%D0%B3%F6%D6%AE%D7%EE%B8%DF%82%DC%D7%F7+%B3%A3%B1P Pantyhose

Www Quickwpthemes 2009 08 Notepad2 En Espanol Quick Wp Themes LJ's Blog

Www Quickwpthemes 2009 08 Notepad2 En Espanol Quick Wp Themes

2009 Notepad2 searchsearch 2009 u Espanol c Espanol wpsearch Notepad2 ssearcha Www s Www ac Notepad2 searchs%D1%C7%D6%DE%CE%DE%C2%EBAV%CE%C4%B5%B5a Quickwpthemes csearchW w 2009 Notepad2 Quickwpthemes W Www w w Espanol Notepad2 search Www Notepad2 Quickwpthemes searchsearch 2009 searchsearchsearch

单向扫描
int partition(T A[], int p, int q)
{}
 swap(A[p], A[j]);
 return j;
}

双向扫描可以正常处理所有元素相同的情况,而且交换次数比单向扫描要少。

Hoare的双向扫描
int partition(T A[], int p, int q)
{} 
}

需要注意的是,返回值j并不是枢纽元的位置,但是仍然保证了A[p..j] <= A[j+1...q]。这种方法在效率上于双向扫描差别甚微,只是代码相对更为紧凑,并且用A[p]做哨兵元素减少了内层循环的一个if测试。

改进的双向扫描

枢纽元保存在一个临时变量中,这样左端的位置可视为空闲。j从右向左扫描,直到A[j]小于等于枢纽元,检查i、j是否相交并将A[j]赋给空闲位置A[i],这时A[j]变成空闲位置;i从左向右扫描,直到A[i]大于等于枢纽元,检查i、j是否相交并将A[i]赋给空闲位置A[j],然后A[i]变成空闲位置。重复上述过程,最后直到i、j相交跳出循环。最后把枢纽元放到空闲位置上。

int partition(T A[], int p, int q)
{}
 A[i] = x; // i == j
 return i;
} 

这种类似迭代的方法,每次只需一次赋值,减少了内存读写次数,而前面几种的方法一次交换需要三次赋值操作。由于没有哨兵元素,不得不在内层循环里判断i、j是否相交,实际上反而增加了很多内存读取操作。但是由于循环计数器往往被放在寄存器了,而如果待排数组很大,访问其元素会频繁的cache miss,所以用计数器的访问次数换取待排数组的访存是值得的。

关于双向扫描的几个问题

1.内层循环中的while测试是用“严格大于/小于”还是”大于等于/小于等于”。

一般的想法是用大于等于/小于等于,忽略与枢纽元相同的元素,这样可以减少不必要的交换,因为这些元素无论放在哪一边都是一样的。但是如果遇到所有元素都一样的情况,这种方法每次都会产生最坏的划分,也就是一边1个元素,令一边n-1个元素,使得时间复杂度变成O(N^2)。而如果用严格大于/小于,虽然两边指针每此只挪动1位,但是它们会在正中间相遇,产生一个最好的划分,时间复杂度为log(2,n)。

另一个因素是,如果将枢纽元放在数组两端,用严格大于/小于就可以将枢纽元作为一个哨兵元素,从而减少内层循环的一个测试。
由以上两点,内层循环中的while测试一般用“严格大于/小于”。

2.对于小数组特殊处理

按照上面的方法,递归会持续到分区只有一个元素。而事实上,当分割到一定大小后,继续分割的效率比插入排序要差。由统计方法得到的数值是50左右(REF[3]),也有采用20的(REF[1]), 这样原先的QuickSort就可以写成这样

void QuickSort(T A[], int p, int q)
{}
 else
 InsertionSort(T A[], p, q); //user insertion sort for small arrays
}

二、分治

分治这里看起来没什么可说的,就是一枢纽元为中心,左右递归,实际上也有一些技巧。

1.尾递归(Tail recursion)

 

快排算法和大多数分治排序算法一样,都有两次递归调用。但是快排与归并排序不同,归并的递归则在函数一开始, 快排的递归在函数尾部,这就使得快排代码可以实施尾递归优化。第一次递归以后,变量p就没有用处了, 也就是说第二次递归可以用迭代控制结构代替。虽然这种优化一般是有编译器实施,但是也可以人为的模拟:

void QuickSort(T A[], int p, int q)
{} 
}

采用这种方法可以缩减堆栈深度,由原来的O(n)缩减为O(logn)。

 

三、参考文献:

jackaldire.com/200908/quick-sort-analysis/

Jun 9

随机函数

程序设计随笔 0 Comments

 随机函数的实现

        在编程过程中经常要用到随机数,通过调用库函数rand()来产生随机数。在调用rand()函数前一般要先调用 srand (unsigned int seed)产生随机种子。seed的选取一般可以采用系统时间来设置。产生随机数的范围在0~RAND_MAX。RAND_MAX定义在stdlib.h,其值为32767。

        假如我们要产生10个0~10之间的随机数,可以通过以下方式

 

#include<stdlib.h>
#include<stdio.h>
#include<time.h>

main()
{}
}

 

        关于srand(unsigned int seed)函数和rand()函数是库函数提供给我们的接口,也可以定义自己的函数来模拟这两个函数的实现

 

#include <time.h>
#include <stdlib.h>
#include <stdio.h>

unsigned long int next = 1;

void LJ_srand(unsigned int seed)
{}

int LJ_rand()
{}

main ()
{}

 

rand()函数和srand()函数之间的通信是通过一个全局变量next来交互的,不调用srand()函数时,默认的next的值为1,那么每次产生的随机数是一样的。

参考c programing language

 

 

 

 

Jun 6

转载metal-fan Modular Exponentiation

algorithm 0 Comments

 

  计算大整数的模幂比如 时 会非常大,直接去计算不是好的方法。

 

可以把n用二进制展开式表示 n = 

那么问题就变成了

所以要计算,就要先算出

再把这些当时的的项乘起来。

根据公式

所以只需把的各项 mod m乘起来再除以m取余就能得到结果了。

算法伪码如下:

procedure modular exponentiation(b: integer, n = , m: positive integer)

x := 1 kWww Quickwpthemes 2009 08 Notepad2 En Espanol Quick Wp Themes LJ's Blogt x l Lesbian p Quick Wp Themes A Lingerie rWww Quickwpthemes 2009 08 Notepad2 En Espanol Quick Wp Themes LJ's Blogz v v TS%20Seduction Pantyhose Quick Wp Themes