插入排序: O(n^2),稳定排序
插入排序是在一个已经有序的小序列的基础上,一次插入一个元素。当然,刚开始这个有序的小序列只有1个元素,就是第一个元素。比较是从有序序列的末尾开始,也就是想要插入的元素和已经有序的最大者开始比起,如果比它大则直接插入在其后面,否则一直往前找直到找到它该插入的位置。如果碰见一个和插入元素相等的,那么插入元素把想插入的元素放在相等元素的后面。所以,相等元素的前后顺序没有改变,从原无序序列出去的顺序就是排好序后的顺序,所以插入排序是稳定的。
void
insert_sort(int *array, int len)
{
int i, j, backup;
for(i=1; i<=len-1; ++i) {
backup = array[i];
for(j=i-1; j>=0 && array[j]>backup; --j)
array[j+1] = array[j];
array[j+1] = backup;
}
}
void
insert_sort_recursive(int *array, int len)
{
if(len == 1)
return;
insert_sort_recursive(array, len-1);
int j, backup = array[len-1];
for(j=len-2; j>=0 && array[j]>backup; --j)
array[j+1] = array[j];
array[j+1] = backup;
}
选择排序: O(n^2),非稳定排序
选择排序是给每个位置选择当前元素最小的,比如给第一个位置选择最小的,在剩余元素里面给第二个元素选择第二小的,依次类推,直到第n-1个元素,第n个元素不用选择了,因为只剩下它一个最大的元素了。那么,在一趟选择,如果当前元素比一个元素小,而该小的元素又出现在一个和当前元素相等的元素后面,那么交换后稳定性就被破坏了。比较拗口,举个例子,序列5 8 5 2 9, 我们知道第一遍选择第1个元素5会和2交换,那么原序列中2个5的相对前后顺序就被破坏了,所以选择排序不是一个稳定的排序算法。
void
select_sort(int *array, int len)
{
int i, j, min;
for(i=0; i<len-1; ++i) {
min = i;
for(j=i+1; j<=len-1; ++j)
min = array[min] < array[j] ? min : j;
if(min != i)
swap(array+min, array+i);
}
}
冒泡排序: O(n^2)时间复杂度,稳定排序
冒泡排序就是把小的元素往前调或者把大的元素往后调。比较是相邻的两个元素比较,交换也发生在这两个元素之间。所以,如果两个元素相等,我想你是不会再无聊地把他们俩交换一下的;如果两个相等的元素没有相邻,那么即使通过前面的两两交换把两个相邻起来,这时候也不会交换,所以相同元素的前后顺序并没有改变,所以冒泡排序是一种稳定排序算法。
void
swap(int *a, int *b) /* precondition: pointer a and b can't be the same */
{
*a = *a + *b;
*b = *a - *b;
*a = *a - *b;
}
void
bubble_sort(int *array, int len)
{
int i, j;
for(i=0; i<len-1; ++i) {
for(j=len-1; j>i; --j) {
if(array[j-1] > array[j])
swap(array+j-1, array+j);
}
}
}
下半年就要正式找工了,淘宝的实习因为爷爷去世提前告一段落。
书籍
编程语言: 《C和指针》,《C专家编程》,《C++ Primer》,《Effective C++》
数据结构与算法: 《算法导论》,《编程珠玑》,《编程之美》
操作系统: 《操作系统》,《深入理解计算机系统》,《Linux内核设计与实现》
计算机网络: 《TCP/IP详解 卷一》
编程实践
常用数据结构,排序,搜索,图算法,动态规划,字符串等
参考: PKU已做题目,何海涛的面试100题,IT面试题
题目:
题目:在数组中,数字减去它右边的数字得到一个数对之差。求所有数对之差的最大值。例如在数组{2, 4, 1, 16, 7, 5, 11, 9}中,数对之差的最大值是11,是16减去5的结果。
对于分治算法,实现的不好,参考原作者的思路,对于左半部分最大值、右半部分最小值都是可以在递归里求出的,参考:
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<limits.h>
#define MAX(a, b) ((a)>(b) ? (a) : (b))
#define MIN(a, b) ((a)<(b) ? (a) : (b))
/*
* 题目:
* 在数组中,数字减去它右边的数字得到一个数对之差。求所有数对之差的最大值
* 例如:
* 在数组{2, 4, 1, 16, 7, 5, 11, 9}中,数对之差的最大值是11,是16减去5的结果
*/
int
naive_solution(int *array, int len) //O(n^2)
{
int i, j, ret = INT_MIN;
for(i=0; i<len; ++i)
for(j=i+1; j<len; ++j)
ret = MAX(ret, array[i]-array[j]);
return ret;
}
int
divide_and_conquer_solution(int *array, int begin, int end) //O(nlogn)
{
if(begin >= end)
return INT_MIN;
int i, ret, left_ret, right_ret, left_max, right_min, mid;
mid = begin + ((end-begin)>>1);
left_ret = divide_and_conquer_solution(array, begin, mid);
right_ret = divide_and_conquer_solution(array, mid+1, end);
left_max = array[begin];
for(i=begin+1; i<=mid; ++i)
left_max = MAX(left_max, array[i]);
right_min = array[end];
for(i=end-1; i>mid; --i)
right_min = MIN(right_min, array[i]);
ret = MAX(left_ret, right_ret);
ret = MAX(ret, left_max-right_min);
return ret;
}
int
dynamic_programming_solution(int *array, int len) //O(n)
{
int i, cur_ret, cur_min;
cur_ret = array[len-2] - array[len-1];
cur_min = MIN(array[len-2], array[len-1]);
for(i=len-3; i>=0; --i) {
cur_ret = MAX(cur_ret, array[i]-cur_min);
cur_min = MIN(cur_min, array[i]);
}
return cur_ret;
}
int
main(int argc, char **argv)
{
int i, num, *data = NULL;
scanf("%d", &num);
assert(num>=2);
data = (int *)malloc(sizeof(int) * num);
assert(data != NULL);
for(i=0; i<num; i++)
scanf("%d", data+i);
printf("naive_solution result: %d\n", naive_solution(data, num));
printf("divide_and_conquer_solution result: %d\n", divide_and_conquer_solution(data, 0, num-1));
printf("dynamic_programming_solution result: %d\n", dynamic_programming_solution(data, num));
free(data);
return 0;
}
摘要: 来源: http://coolshell.cn/articles/4990.html月光博客6月12日发表了《写给新手程序员的一封信》,翻译自《An open letter to those who want to start programming》,我的朋友(他在本站的id是Mailper)告诉我,他希望在酷壳上看到一篇更具操作性的文章。因为他也是喜欢编程和技术的家伙,于是,我让他把...
阅读全文
问题:
Given a random number generator which can generate the number in range (1,5) uniformly. How can you use it to build a random number generator which can generate the number in range (1,7) uniformly?
(给定一个随机数生成器,这个生成器能均匀生成1到5(1,5)的随机数,如何使用这个生成器生成均匀分布的1到7(1,7)的数?)
解法一:
拒绝采样定理
简单的说, 把 1-5 的随机数发生器用两次, 拼成一个5进制的数, 就是1-25. 将这 1-25 平均分配的25种情况映射到7种情况上, 问题就解决了. 因为21是7的倍数, 我们可以每三个映射到一个, 即1-3 映射到1, …, 19-21 映射到7. 可见, 这些情况之间的概率是一样的. 那么, 要是拼成的数字正好是 22-25 这四个呢? 有两种方法, 第一种是丢弃这个数字, 从头再来, 直到拼成的数字在1-21之间. 因为这个是个概率算法, 不能保证每次都能落在1-21, 所以采样的密度不高. 还有一种方法, 是说, 假如落到了 22-25, 那这次的采样结果就用上次的. 可以证明, 这看上去两个互相矛盾的算法, 结果都能均等的得到等概率的分布. (前者叫做 Reject Sampling, 后者叫做 Metropolis Algorithm, 都是数学物理模拟里面常用的方法)
解法二:
二进制
1-2映射到0,3跳过,4-5映射到1
生成三位的二进制即可
问题来源: 编程珠玑
解法一:
遍历这n个items,巧妙地利用概率来筛选
void
generate_random_m_from_n(int n, int m)
{
int i, remaining, select = m;
srand(time(NULL));
for(i=0; i<n; i++) {
remaining = n - i;
if(rand()%remaining < select) {
printf("%d\t", i);
--select;
}
}
printf("\n");
}
解法二:
shuffle,即随机洗牌程序,然后选择前m个items即可
代码参考:
http://blog.fuqcool.com/2011/04/17/algorithm-shuffle.html
作者:fuqcool 发布时间:2011-04-17 23:16:02 分类: algorithms
最近自己在做一个小的程序,需要把一个集合里面的元素全部随机地打散。自己想了一个方法,复杂度是n,觉得不太快。后来参照了一下python关于shuffle的算法,发现我的方法跟它的是一样的,连python的代码都这么写,可能已经没有办法再快了吧!
下面就来介绍洗牌算法,用C语言描述。
算法的前提是有一个产生随机数的函数
// Generates a random integer between beg and end.
int GetRandomNumber(int beg, int end);
还有一个交换函数。
// Swap a and b.
void Swap(int a, int b);
上面两个函数我就不写出实现了,因为这篇文章的重点在于算法的讨论。
假设我们有一堆扑克牌,怎么才能把这副牌完全打乱呢?计算机当然不能像人手那样洗牌。但是它可以产生随机数,随机地从一副牌中抽出一张牌是可以的。既然这样那就好办了,我们不停地从牌堆中随机抽取一张扑克牌,然后把这些牌堆起来,直到原来的牌堆只剩下一张牌的时候为止。这样不就完成了洗牌的动作了吗。
下面是C代码:
int Shuffle(int[] a, int len)
{
for (int i = len - 1; i > 0; i--)
{
// Select an element from index 0 to i randomly;
int index = GetRandomNumber(0, i);
// exchange a[i] with a[index]
Swap(a[index], a[i]);
}
}
顺便也贴出python的random单元关于shuffle的实现:
def shuffle(self, x, random=None, int=int):
"""x, random=random.random -> shuffle list x in place; return None.
Optional arg random is a 0-argument function returning a random
float in [0.0, 1.0); by default, the standard random.random.
"""
if random is None:
random = self.random
for i in reversed(xrange(1, len(x))):
# pick an element in x[:i+1] with which to exchange x[i]
j = int(random() * (i+1))
x[i], x[j] = x[j], x[i]