404频道

学习笔记

[TOC]

近期准备复习数据结构和算法的知识,参照了网络上各路大神的学习攻略,大部分算法学习的思路为参照一些经典书籍(如算法导论)并结合一些代码的实践来完成,并未找到一条适合我的算法学习之路。经过思考后决定采用代码编写曾经的教科书中代码实例的方式来学习,曾经接触的算法教科书包括《数据结构(C语言版)》和《计算机算法基础》。一来这些算法已经基本熟悉,只是时间久远有些已经忘记;二来,通过思考后编写代码增强自己的记忆。

同时我编写的这些实例可以作为leetcode上的很多题目的基础,为下一个阶段刷leetcode上的题目打好基础。

树的存储形式包括了顺序存储(采用数组形式)和链式存储,其中链式存储更为灵活,可以表示任意形式的树,本文中的代码将采用树的链式存储方式。

树的构建

树的构建有多种方式,本文使用字符串采用了自顶向下、自左到右的顺序构建树,跟leetcode的形式一致。其中’#’表示该节点为空,如果该节点为空节点,其左右子孩子节点也要用’#’表示,而不能不用任何字符表示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/**
* 二叉树的链式存储结构
*/
struct TreeNode
{
char data;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(char data) : data(data), left(NULL), right(NULL) {}
};

/**
* 构造二叉树,要构造的字符串采用了自顶向下、自左到右的顺序,跟leetcode的形式一致
*/
TreeNode *create_binary_tree(const char *str)
{
if (!str || strlen(str) == 0)
{
return NULL;
}

// 对每个节点分配存储空间
int node_size = strlen(str);
TreeNode **tree = new TreeNode*[node_size];
for (int i=0; i<node_size; i++)
{
if (str[i] == '#')
{
tree[i] = NULL;
}
else
{
tree[i] = new TreeNode(str[i]);
}
}

for (int i=0, j=0; i<node_size && j<node_size; i++)
{
if (tree[i] != NULL)
{
if ((j + 1) < node_size)
{
tree[i]->left = tree[++j];
tree[i]->right = tree[++j];
}
}
else
{
j += 2;
}
}
return *tree;
}

二叉树的先序遍历

递归实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 先序遍历二叉树的递归形式
*/
void preorder_traverse_recursion(TreeNode *root)
{
if (!root)
{
return;
}

printf("%c\t", root->data);

preorder_traverse_recursion(root->left);

preorder_traverse_recursion(root->right);
}

非递归实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
* 先序遍历的非递归形式
*/
void preorder_traverse_not_recursion(TreeNode *root)
{
if (!root)
{
return ;
}
std::stack<TreeNode *> tree_stack;
tree_stack.push(root);
while (tree_stack.size() > 0)
{
TreeNode *node = tree_stack.top();
tree_stack.pop();
printf("%c\t", node->data);
if (node->right != NULL)
{
tree_stack.push(node->right);
}
if (node->left != NULL)
{
tree_stack.push(node->left);
}
}
}

二叉树的中序遍历

递归实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 中序遍历二叉树的递归形式
*/
void inorder_traverse_recursion(TreeNode *root)
{
if (!root)
{
return;
}

inorder_traverse_recursion(root->left);

printf("%c\t", root->data);

inorder_traverse_recursion(root->right);
}

非递归实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
* 中序遍历二叉树的非递归形式
*/
void inorder_traverse_not_recursion(TreeNode *root)
{
if (!root)
{
return ;
}
std::stack<TreeNode *> tree_stack;
while (root != NULL || tree_stack.size() > 0)
{
// 遍历到左子树的叶子节点
while (root)
{
tree_stack.push(root);
root = root->left;
}

// 遍历栈顶节点
root = tree_stack.top();
tree_stack.pop();
printf("%c\t", root->data);

root = root->right;
}
}

二叉树的后序遍历

递归实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 后序遍历二叉树的递归形式
*/
void postorder_traverse_recursion(TreeNode *root)
{
if (!root)
{
return;
}

postorder_traverse_recursion(root->left);

postorder_traverse_recursion(root->right);

printf("%c\t", root->data);
}

非递归实现

仅用一个栈不能够实现后序遍历非递归算法,需要保存一个上次访问过节点的变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/**
* 后序遍历二叉树的非递归形式
*/
void postorder_traverse_not_recursion(TreeNode *root)
{
if (!root)
{
return ;
}
std::stack<TreeNode *> tree_stack;
TreeNode *visited = NULL;
while (root != NULL || tree_stack.size() > 0)
{
// 遍历到左子树的叶子节点
while (root)
{
tree_stack.push(root);
root = root->left;
}

root = tree_stack.top();

if (root->right == NULL || root->right == visited)
{
// 如果没有右孩子,或者右孩子刚刚访问过,则访问当前节点
printf("%c\t", root->data);
tree_stack.pop();
visited = root;
root = NULL;
}
else
{
root = root->right;
}
}
}

总结

二叉树遍历的递归形式程序结构类似,编写相对简单。但是递归方法在C语言中存在执行效率差(需要维护函数栈),容易出现栈溢出的异常的问题。任何递归问题问题都可以转化为非递归问题,转化的思路包括了直接转化法和间接转化法。直接转化法可以通过循环来解决,间接转化法需要借助栈加循环来解决。

二叉树遍历的非递归形式相对复杂,二叉树的先序遍历的非递归形式容易理解,二叉树的中序遍历稍微困难,后序遍历的非递归形式最复杂。

相关下载

程序源代码

在Windows下可以通过计算器进行进制之间的转换,非常方便。本文总结Linux下可用的进行进制之间的转换方法。

利用shell

shell脚本默认数值是由10进制数处理,除非这个数字某种特殊的标记法或前缀开头,才可以表示其它进制类型数值。如:以0开头就是8进制、以0x开头就是16进制数。使用“BASE#NUMBER”这种形式可以表示其它进制。BASE值的范围为2-64。

其他进制转10进制

1
2
3
4
5
6
7
8
9
10
11
12
kuring@T420:~$ echo $((16#4000000))
67108864
kuring@T420:~$ echo $((2#111))
7
kuring@T420:~$ echo $((0x10))
16
kuring@T420:~$ echo $((010))
8

// 对进制转换为10进制进行运算,稍显啰嗦
kuring@T420:~$ echo $(($((16#4000000))/1014/1024));
64

利用let命令

let用来执行算数运算和数值表达式测试。可以利用该命令完成简单的计算,并将计算结果赋给其他变量。

1
2
3
4
// 对进制转换为10进制后进行运算,比纯shell方式简洁
kuring@T420:~$ let a=$((16#4000000))/1014/1024;
kuring@T420:~$ echo $a
64

利用bc命令

该命令是一个强大的计算器软件,可以利用其中的ibase和obase进行输入进制的转换,ibase表示输入数字的进制,obase表示输出数字的进制。

1
2
3
4
5
6
// 如果没有制定,则默认为10进制
// 对于16进制,要使用F,而不能使用f
kuring@T420:~$ echo "ibase=16;FF" | bc
255
kuring@T420:~$ echo "obase=2;ibase=16;FF" | bc
11111111

参考文章

linux shell 不同进制数据转换(二进制,八进制,十六进制,base64)

Shell进制转换小结

题目

Memory Limit Exceeded

Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.

push(x) – Push element x onto stack.
pop() – Removes the element on top of the stack.
top() – Get the top element.
getMin() – Retrieve the minimum element in the stack.

错误代码

看到此题目,以为是用实现一个简单的栈结构,于是就直接写下了如下代码,采用了双向链表的方式来实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
class MinStack {
public:
struct Node
{
int data;
Node *next;
Node *pre;
Node() : next(NULL),pre(NULL) {};
};

MinStack()
{
header = new Node();
tail = header;
}

void push(int x) {
Node *node = new Node();
node->data = x;
node->pre = tail;
tail->next = node;
tail = node;
}

void pop() {
Node *pre = tail->pre;
delete tail;
tail = pre;
tail->next = NULL;
}

int top() {
if (tail == header)
{
return -1;
}
return tail->data;
}

int getMin() {
Node *begin = header->next;
int min = INT_MIN;
while(begin)
{
if (min > begin->data)
{
min = begin->data;
}
begin = begin->next;
}
return min;
}

private:
Node *header;
Node *tail;
};

提交后提示Memory Limit Exceeded错误,开始考虑是不是双向链表占用的空间过多。

正确代码

仔细看题目后发现retrieving the minimum element in constant time,即时间复杂度为O(1),上述实现代码时间复杂度为O(n),明显不符合要求。看来理解题目有误,不是为了实现栈类,而是为了利用数据结构解决获取最小值问题。

经过考虑后可以通过在类内部维护存储最小值的栈来解决,存储最小值的栈除了需要存储最小值外,还需要维护最小值个数。

实现代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
class MinStack {
struct MinUnit
{
int count;
int value;
MinUnit(int count, int value) : count(count), value(value) {};
};
public:
void push(int x) {
data_stack.push(x);
if (min_stack.empty() || x < min_stack.top()->value)
{
MinUnit *p_unit = new MinUnit(1, x);
min_stack.push(p_unit);
}
else if (x == min_stack.top()->value)
{
min_stack.top()->count++;
}
}

void pop() {
if (data_stack.top() == min_stack.top()->value)
{
if (min_stack.top()->count == 1)
{
MinUnit *punit = min_stack.top();
min_stack.pop();
delete punit;
}
else
{
min_stack.top()->count--;
}
}
data_stack.pop();
}

int top() {
return data_stack.top();
}

int getMin() {
return min_stack.top()->value;
}

private:
std::stack<int> data_stack;
// 最小栈,为了便于修改栈单元中的count值,采用存储指针方式
std::stack<MinUnit*> min_stack;
};

由于I/O模型现在掌握还不够透彻,本文仅列出了一些I/O模型中的一些常用概念,对于select、poll、epoll和信号驱动I/O等模型理解还不够透彻,待理解透彻后补上。

阻塞I/O与非阻塞I/O

阻塞I/O:当进行I/O操作后,程序处于等待状态,直到需要的资源可用为止。

非阻塞I/O:当进行I/O操作后,函数直接返回,不需要等待。

两种文件描述符准备就绪的通知模式

水平触发通知:如果文件描述符上可以非阻塞地执行I/O系统调用,此时认为它已经就绪。允许在任意时刻重复检测I/O状态,没有必要每次当文件描述符就绪后尽可能多的执行I/O。其中select()和poll()属于水平触发通知模式。

边缘触发通知:如果文件描述符自上次状态检查以来有了新的I/O活动,此时需要触发通知。只有当I/O事件发生后才会得到通知,在另外一个I/O事件到来之前不会得到通知。因此,在接收到一个I/O事件后,程序在某个时刻应该在相应的文件描述符上尽可能多地执行I/O。每个被检查的文件描述符被置为非阻塞模式,在得到I/O事件通知后重复执行I/O操作,直到系统调用返回错误为止。其中信号驱动I/O属于此种类型。

将的通俗一点,假设通过异步I/O读取socket数据,当接收到100个字节的数据后,这时候会触发通知给应用程序。如果应用程序仅读取了50字节的数据,重新调用异步I/O函数时,在水平触发时仍然会得到通知,而采用边缘触发时不会得到通知。

epoll即可以采用水平触发通知方式,也可以采用边缘触发通知方式。

这两个概念对于理解Linux的I/O模型非常重要,但是却是不容易理解。可以通过举例说明:一个管道内收到了数据,注册该管道描述符的epoll返回,但是用户只读取了一部分数据,然后再次调用了epoll。这时,如果是水平触发方式,epoll将立刻返回,因为当前有数据可读,满足IO就绪的要求;但是如果是边沿触发方式,epoll不会返回,因为调用之后还没有新的IO事件发生,直到有新的数据到来,epoll才会返回,用户可以一并读到老的数据和新的数据。

同步I/O与异步I/O

同步I/O:发出I/O操作后,后面操作不能进行,要么等待I/O操作完成,要么放弃I/O操作。后面的操作和当前的操作只能有一个进行。

异步I/O:发出I/O操作后,马上返回继续执行后面的操作,而I/O操作同时执行。

参考文章

云南

前言

在这个炎热的夏天,在一个特殊的月份,我开启了一段8天7晚的云南之旅。出于资金方面和省心方面的考虑,选择跟团旅游。本次的旅行包含了昆明、大理、丽江和香格里拉四个地点,如果不是跟团,在短短的6天的旅行时间之内不可能走完四个地方的多个景点,因为这四个地方之间的距离坐车基本都在四个小时以上。大多数人去云南还是会选择跟团的,因为跟团省太多事了。如果是独自出行,每天光查路线路、找酒店、查攻略就会浪费掉很大一部分时间,肯定会更自由一些,但是绝对不会走过这么多地方。

跟团也有很多不好的地方,本次出行旅行社制定的路线为“出发地-昆明-大理-丽江-香格里拉-丽江-大理-昆明-目的地”,可以看到路线是重复了一遍,相当于很大一部分时间都浪费在了路上,至少相当于浪费了4+4+4共12个小时的时间,这也就造成了每天早晨需要很早就起床,基本在6点半就坐在大巴上出发了。之所以每天早晨会很早就起床,另一个原因是因为现在是云南旅游的旺季,一旦稍微晚些,很多景点就会排队等好长时间,可能晚起10分钟,就要在景区多排一个小时的队。

跟团的价格之所以便宜,听导游说,这是云南省旅游局的决定。云南绝大多数都是高原山区地貌,交通不够发达。旅游业在云南的经济中占有很大的比重,政府想通过旅游来拉动经济,跟团价格便宜,自然需要在旅游过程中的消费来赚钱。本次旅游的过程中,也有几次购物的经历,其中行程中的大理十八里铺和七彩云南是赤裸裸的购物环节,导游也明确的告知了。在去景点的过程中,很明显发现每个景点的必经通道中均有购物的部分,这是云南的景点和我去过的其他景点比较大的差别。最奇葩的是长江第一弯的观景楼,大约7层楼左右的样子,每层楼的楼梯都不在一个位置,从一层的楼梯走到另一层的楼梯必经卖土特产的柜台,楼层上全是卖土特产的。其实长江第一弯也仅有一个观景楼而已,因此是免费的。

跟团很大一部分时间都在坐车上,游览景点的时间确实非常紧,而导游给的购物地方的时间确实非常充裕。比如游览石林仅给了一个半小时左右的时间,石林是国家的5A级景区,门票价格是170,是本次行程中最贵的景点了吧。石林虽然不大,但是要想在一个半小时内全部游览完是不可能的,因此只能走马观花,没办法,跟团走就只能认了。

之所以要写下这段行程,是因为这段旅行对我而言有着不一般的意义,我想将这段记忆铭记在心。不幸的是,回家后发现单反的SD卡出问题了,照片丢失了很大一部分。我虽不是很认同旅游就是为了拍照,现在人们已经过度的重视拍照而忽略了旅行本身的意义,但是这些照片在这次旅行中确实不可或缺的。


Day 1

下午三点多就到了春城昆明,抬头一看昆明的天果然不一般,云彩非常多,而且离地面非常近,轮廓感很强。阳光非常强烈,气温虽然不高,但是紫外线较强,阳光照在皮肤上生疼。不像在济南只能看到的雾霾,济南即使有云也是在雾霾之上,从地面看去毫无层次感。找到旅行社后机场接送人员送往酒店,稍事休息后去到昆明市中心的南屏街。从整体看,昆明的市容跟济南相仿,属于不是很繁华的类别,但是却属于省会的档次。下图照片我第一晚酒店的照片,大家感受一下云。

金生源

晚上和朋友在一家彝族的菜馆吃饭,对于北方的我来说,南方的饭菜吃起来不太习惯,米饭是生硬的,汤是油腻的,菜是辣的且没滋味。

吃完饭后准备坐公交回酒店,已经晚上九点半左右了,想抬头看看能不能看到星星,居然看到满天的云,真是奇特。在山东即使晚上有满天的云,也绝对达不到昆明的云的明亮程度。造成这种现象有两个原因,一是昆明属于东七区,比北京时间要晚上一个小时;二是,云南的云离得地面更近且多。


Day 2

这是悲催的一天,按照行程,要走“昆明—大理—丽江(昆明大理行车约4.5小时,大理-丽江行车约2小时车程)”的路程。早晨一起床,要去餐厅吃早饭,发现餐厅乌秧乌秧的全是人啊,找个地方吃饭都难,在艰难中吃完了早餐。期间一女同胞不小心打碎了一个碗,餐厅老板要了女顾客10块钱,心想真黑啊,几毛钱一个碗至于要这么多吗?

吃完饭后,餐厅外面和酒店大堂全是游客,经过电话沟通后找到了导游。导游点名后坐上了悲催的大巴。幸运的是,导游还不错,东北小伙,在云南上的大学。云南的旅游大巴都是车牌号都是统一编号的,车牌号以“L“开头,表示旅游的含义。旅游大巴启动后,雨就开始稀里哗啦的下起来了,运气还不错。

旅游大巴在高速上要在好多地方做例行检查,大约9点左右行驶到楚雄地段的某个高速检查点时,我们大巴的右侧玻璃跟后面的大巴的左侧后视镜摩擦而过,因为我就坐在后排,眼睁睁的目睹了这一过程。结果我们大巴右侧玻璃和后面大巴的左侧后视镜全部挂掉了,幸好没有驴友受伤情况,有图有真相。

旅游大巴

在服务区经过1个小时的等待后大巴向前走了,目的地不是大理,而是前方的某个小镇。因为大巴没了挡风玻璃,速度也上不去了,在后面坐着还是相当凉快的。在小镇吃了个野生菌火锅后,开始了漫长的等待,等待着更换的大巴从大理赶来。从出现事故到新的大巴的到来,花掉了近5个小时的时间,这五个小时就算浪费了。

大巴前往大理,到达大理时接近5点多了,在天龙八部影视城附近吃了个晚餐,开始了赶往丽江的行程。本来计划中的大理古城和束河古镇全部泡汤,只能将行程安排到回来时在游览。

到达丽江时已经晚上十点的样子,刚刚下过一场雨,直接入住酒店。


Day 3

相对来说最轻松的一天,今天的行程中仅有玉龙雪山景区和玉水寨。

在云南给我们带团的导游属于省级导游,到了丽江这种地方性景点导游需要更换为地方性导游,这也是一种地方拉动就业的措施。昨天的导游直接休息一天,今天的导游是当地的纳西族导游带领。

玉龙雪山是丽江旅游的必去之地,每天丽江的游客大约在2万人的样子,也就意味着每天也会有2万人会前往玉龙雪山。为了避免在景区排队,早晨6点半就出发前往玉龙雪山,一个小时左右时间到达了玉龙雪山的入口。下车后坐着环保大巴盘山而上,到达云杉坪脚下,乘索道而上到达云杉坪。云龙雪山终年云雾缭绕,尤其是在云南的雨季更是非常难以看到玉龙雪山的面貌,听导游讲他也仅仅看过10次左右的样子。我不是个幸运的人,自然也无法看到玉龙雪山的面貌,此时天还下着小雨,从云杉坪上望去仅有白茫茫的云而已。其实从索道下和索道上看到的玉龙雪山的景色几乎是完全一致的,增加索道仅是为了增加景点的可玩性。

玉龙雪山

从索道下来后,开始乘坐电瓶车往下走,经过三站,每一站都会停下来观赏风景。三站观赏都是下山的白水河,只是分为了三段,三段景色不尽相同。河水属于碱性,河水颜色是蓝色且清澈,看起来相当漂亮,所以叫做蓝月谷。

蓝月谷1

蓝月谷2

蓝月谷3

从雪山下来后,如果时间来的及可以看到张艺谋导演的《印象丽江》,500名纳西族的群众演员的表演。由于下来晚了,仅看了个5分钟的结尾,不过可以从网上找的到视频。自从有了老谋子的《印象丽江》,带团的必须跟着演出时间走,来晚了就看不上了。

从云龙雪山出来后,前往玉水寨。玉水寨是丽江古城河水主要源头之一,是丽江东巴文化的传承圣地。景点面积不大,但属于东巴教圣地。既然属于圣地,照片就不上了。

在回丽江市的途中,导游领我们去了所谓的螺旋藻配送中心,实实在在的购物环节。螺旋藻的确属于丽江特产,野生的螺旋藻需要生长在碱性环境中,而离丽江不远的程海湖是世界第三大碱性湖泊,绝对是野生螺旋藻的产地,就是不知道市面上的所谓程海湖螺旋藻有多少是真的,因为一个程海湖再大也供应不了市场上这么多的螺旋藻。螺旋藻可以被导游描述出一堆好处,什么降血压、调肠胃、增强抵抗力等。每罐螺旋藻290元,属于批发价。机灵的我在没有了解一件商品之前是不会冲动消费的,淘宝一下发现有更便宜的,好像这个品牌也不是什么最好的,自然不买,何况想买还非得从这里买不成。

下午一点左右到达丽江古城北门后就是我们的自由时间。首先来到了黑龙潭公园,属于市民最常去的健身场所,跟济南的五龙潭公园类似,没什么特别之处,属于市民最常去的健身场所。

黑龙潭公园

从黑龙潭出来后直奔丽江古城,整个游览下来丽江古城给我的感觉就是一座已经完全商业化的现代古城,几乎跟我想象中的一致。导游跟我们说过,丽江古城内其中90%是外地人,因此要在这里找回古城的感觉是比较难了,但在这里文艺一把还是可以的。

丽江古城面积虽大,但是游览下来古城内也就文艺客栈、普通餐馆、艳遇酒吧、彩条围巾、特色小饰品、银首饰、手敲鼓、写真。客栈几乎被鲜花包裹,随便找一家客栈都看上去很美很艺术,看上去像是一件艺术作品。餐馆跟古城外面的没什么两样,只是位置不同罢了。酒吧在古城中占有很大一部分席地,丽江是以艳遇闻名的,艳遇最多的地方还是得在酒吧。甚至大街上都有卖艳遇服装的,可见艳遇在游客心中的地位。彩条围巾基本拿回家都是送人和当桌布的,导游说围巾基本都产自浙江的,但在逛古城的时候买个披肩披在身上看起来还是不错的。导游说银首饰是买不得的,不知真假,不买为好。从店外面看去手敲鼓店里在边劈着腿坐着敲鼓边唱歌的女士怎么看怎么觉得别扭,但那音乐很特别。古城的街道挺多,但是走着走着却厌倦了,因为每条街道上的商品也就那些。

丽江古城客栈
丽江古城酒吧
丽江古城路标
丽江古城街道

边看地图边问路,再配合上不太好用的百度地图向酒店返回。丽江的特色菜为三文鱼、黑山羊和腊排骨。一路上想找一家可以吃腊排骨的店,愣是没有找到一家合适的。最后累并饿的不行了,在四方街找了家德克士填饱肚子算了。


Day 4

一早起来,发觉胃部不适,不知是不是昨天在丽江古城吃了什么不合适的小吃还是晚上睡觉忘记开窗户了还是有点轻微的高原反应还是这几天的劳累还是水土不服。总之身体不舒服是旅游中的大忌,我恰巧就碰到了。稍微喝了点米粥后就上路了。约莫走了一个小时,吐了一次。还好,吐完后整个身体都轻松多了。

在虎跳峡附近接上我们的香格里拉导游,地方导游自然是藏族人,叫什么措,我们的团改成叫“措团”。

今天第一个景点为虎跳峡,虎跳峡为金沙江上的一个峡谷,下车点在峡谷上方,景点为沿着护栏峡谷底部行进,到达底部后再沿上行木栈道到达出发点。下车后听到最多的就是知了叫,知了数量非常之多,以至于木栈道上都有,伸手就可以抓到。沿木栈道而下,江水并没有想象中的急,不过在最下面的观景台上声音听起来确实很大。观景台对面有一个连接两山的石桥远远看去非常漂亮。由于照片全部损坏,不能贴图了。

从虎跳峡走后下午一点抵达“心中的日月–香格里拉”,香格里拉一名源于《消失的地平线》小说中虚构的地名。香格里拉的海拔在3200米,很多人在这种海拔高度会出现高原反应。

下午一到酒店就趴在床上累的起不来了,沉睡了两个小时后,由于晚上要去藏族家里进行家访,不敢睡的太沉。醒后又在床上躺了一个多小时,一闭眼就能睡着,感觉从来没有这么累过。咬咬牙起来后,找个超时买点东西,感觉走起来也非常的累,心想,这辈子再也不会来这地方了,纯粹的花钱找罪受。

吃过晚饭后,就去了藏族家。这个是额外收费的,而且费用不低。带牦牛肉和烤鸡肉的价格为一人260元,不带的为一人180元。胃部本来就不适的自然选择了180元的价格。等到我们去了之后问起其他团的,他们带牦牛和烤鸡的价格才100元,可见我们导游能黑我们多少money。这次家访纯粹是一次商业性质的家访,大巴在藏族家门口停下来,下车后就会有人给佩戴围巾,并且有专人拿着单反拍照。

进屋后直接到二楼,屋里已经有好多个团围着屋中央而坐。坐下后,品尝酥油茶,青稞酒,还有酸奶干,甚至还有青稞拿来当瓜子吃的。

等牦牛肉和烤鸡都上齐后,节目就开始了。主持人很明显经过些专业的训练,嗓门特别大,也特别擅长带动气氛。藏族人好客的方式就是跺地板加鼓掌,声音越大越好。地板为木制的,一群人跺起脚来后声音特别大。节目大约持续了三个小时,无非就是跳舞、唱歌、跺脚、教些藏族的语言等。其实节目挺无聊,但是热闹。挺佩服主持人能够将这么庸俗的一个节目坚持了三个小时之巨。本来身体非常难受的我,在欢呼中也变得热情高涨,使劲跺脚,使劲故障,全身心投入到节目中,最后居然难受的症状全部消失了。

期间,藏民开始按照在门口时拍摄的照片找人,所有人的照片早已经洗好,并且用硬塑料膜保护着。照片20元一位,可见这是多么商业的一次活动。

到了酒店已经11点了,导游嘱咐过不能早睡,不能洗澡,否则很容易出现高原头痛等高原反应的症状。


Day 5

照旧是早起,今天的行程为普达措国家森林公园。为了防止出现高原反应带来的事故,同时也可以达到赚钱的目的,导游推荐我们在香格里拉买氧气灌和红景天口服液。仙剑奇侠传三中的景天大概就取自此药名吧。普达措的最高处海拔可以达到4200米,想想这个海拔高度,为了避免高原反应,再加上昨天我本来就很不舒服,为了保险了我买了两罐,并且购买了一盒红景天口服液。后来才发现这些花费都是多余的,普达措之所以称之为森林公园,森林肯定非常之多,空气中氧气含量不会很低。走在普达措中,感觉空气比氧气瓶中的更纯净。

整个森林公园分为了三部分:属都湖、弥里塘和碧塔海。整个森林公园的面积非常之大,三个景点之间大约需要坐10-20分钟的电瓶车,电瓶车上都会有导游对景点进行讲解。

普达措应该是我这次云南旅游中最值得一去的地方,整个游览下来就感觉这个地方好似人间仙境。这里的湖面非常静,远处牦牛和马儿低着头在不停的吃草,一副悠闲自得的样子。遍地的小野花,在牛粪堆中自由的生长。从山上留下来的水就在平地上冲出一条弯弯曲曲的河,令我一直在想河道为什么是S型,这说明山上留下来的水总是缓缓的。水杉树上挂满了蜘蛛网版的白色的毛,更添加了这里的仙境色彩,据说是寄生在水杉上的一种植物。山间偶尔会见到特别小的小松鼠在树下找点吃的,然后一会就不见了,仿佛刚才见到的不是真的。这中景色中有身临其境方能体会。

属都湖为一个天然湖泊,远处就能看到牦牛和马儿。弥里塘是整个森林的海拔最高处,地方非常平静,视野相当开阔,牦牛和马儿在远处的草地上吃着小花小草。碧塔海是整个景区的核心景点,我们选择徒步4公里的路程,沿着碧塔海从湖的一边走到另外一边。在漫步中慢慢体会碧塔海的迷人之处。

山间的小河
弥里塘
碧塔海
野花
河

从普达措出来后,藏族导游跟我们说拜拜。在香格里拉吃过午饭后,开始马不停蹄的往丽江赶。期间路过“长江第一湾”景点,在观景楼上高高看去,除了恐高之外没有别的感觉。前文已经介绍过“长江第一湾”景点的一些坑况,不再对坑进行过多描述。

下午三点多到达丽江的酒店,在酒店放下东西后直接前往大理古城,这里酒店离的大理古城的南门算是比较近。上次来没有吃上当地特色小吃腊排骨,在南门外找了家店品尝一番,吃起来跟我想象中的一致,除了有点排骨味之外还略带腊味。

吃完腊排骨后已经是晚上8点左右的时间,上次逛丽江古城主要是逛了北门附近多些,这次逛上次没有逛过的南门附近。南门附近与北门不同的是,古城南边有很多的客栈,但是这里的胡同和客栈却略显凄凉,人少了需要,客栈也没有那么文艺。转了几个胡同后,在转了一个又一个弯后的胡同中找到了大名鼎鼎的木府。时间已晚,看着地图加导航接回酒店睡下了。


Day 6

今天的行程为从丽江-大理-昆明。上次去大理仅是路过,这次是去体验,虽然时间也仅仅有一天。

下关风,上关花,苍山雪,洱海月。风花雪月便是大理景色的最真实写照,大理城就被下关、上关、苍山和洱海包裹着。本次大理执行风花雪月均为体会到,甚至连洱海边都未到过,仅仅是去了洱源小西湖,也勉强算是到过洱海吧。

快到洱源小西湖的路上遇到了集市,集市上有用竹篓子卖小猪,看起来挺滑稽挺有意思。

进入洱源小西湖后导游会先带领到购物区,都是些当地的特产,价格也不贵。刚坐上木船会看到鱼鹰表演,木船绕着西湖转上一圈,欣赏西湖的美景。

下船后,会去餐馆白族的歌舞表演,并品尝白族三道茶。三道茶“头苦、二甜、三回味”,喝起来味道怪怪的。从歌舞表演厅出来后就直接出西湖了。

洱源小西湖
鱼鹰表演
洱源小西湖
三道茶

从西湖出来后,直接赶到白银购物中心十八里铺。大理是白银产地,在大理旅游购物自然少不了白银。一下车,在十八里铺的停车场已经停了几十辆大巴,显然都是拉来购物的。导游象征性的给我们介绍了下大理白族的房屋布置和婚房布置,顺便看了下几个人在手工制作白银,最后就带我们到白银购物大厅里了,然后导游就撤了。留下来选择购买白银的时间非常的长,有一个半小时之久。

艰难的等待后,在十八里铺吃完午饭后,直接奔向大理古城。由于南门无法停车,大巴在离大理古城南门2里地的停车场停下,导游给我们游玩的时间是1个半小时,偌大一个大理古城仅有一个半小时的游玩时间,而一个十八里铺的购物大厅却也预留了差不多时间。

大理古城相比丽江古城更现代化,古城内有相当多的现代商店,甚至都有超市的存在,除了建筑风格比较古之外,其他都是新的。古城的北面,直接就成了居民区了。不过相比丽江古城,我更喜欢大理古城,因为这里购物更方便,而且街道也建设的更加规整,不会出现迷路的情况。里面的物品价格也更加便宜,整个古城更像是城市中的步行街。

古城南门
五华楼
洋人街

从大理古城走后,直接赶回昆明,到达昆明酒店已经是晚上10点了。


Day 7

早餐后赶往中国名牌企业七彩云南,顾名思义就是购物了。导游一而再再而三的强调,导游前五天是天使,第六天就是魔鬼。“什么都可以落在宾馆,唯独你们的武器–钱包不能落在宾馆”。没有比这个更直白的了。

七彩云南园区内共有七个展馆,首先带领我们去的是翡翠馆。翡翠主要产自缅甸和云南接壤地带,自然会成为云南的特产代表。导游带领我们体验一把模拟的翡翠形成过程的动画,紧接着就会带领我们到达翡翠销售大厅。购买翡翠的时间预留的非常充足,期间为了打发时间跑去了孔雀园转了一圈。整个行程中导游是只字未提孔雀园,但是孔雀园却是七彩云南园区中最适合游玩的地方。孔雀园内有几千只孔雀,植物的种类也非常多,还有一面非常大的花墙,看上去也是相当漂亮。

集合后又餐馆了普洱茶馆,直接被关到屋里面品茶,品完熟茶品生茶,品完茶后自然是买茶。

七彩云南
七彩云南地图
孔雀园花墙

在七彩云南吃过午餐后,大巴赶往天造奇观的石林。去石林的路上,从未看到过石林内形状的石头,可是到了石林内部却到处都是竖状的石头,一直对竖状石头的成因感到颇为好奇。一个5A级的景区仅仅预留了一个半小时的时间游览,而且还包含了排队等电瓶车的时间。

石林分大石林和小石林,大石林的石头看上去更高大一些,小石林的石头看上去稍微矮小一些。听景区的导游介绍,到了大石林找到“石林”二子后拍个照后就相当于花掉了100块钱的门票,到了小石林后找到“阿诗玛的化身”后就相当于又花掉了70元的门票。

到达大石林后找到了“石林”二字拍完照后,没有听导游的话直接原路返回坐电瓶车到小石林,而是出于好奇在石林内部转起迷宫来,石林面积应该不小,至少我在内部至少走了40分钟后也没有走多少,而且重要的是我彻底迷路了,找不到入口也找不到出口。一看时间已经过去了一大半,还没到小石林,就抓紧时间往外赶,转了半天迷宫终于出来了。

排队挤上电瓶车到达小石林,小石林石头之间的间隙要大很多,石头之间还有草地,走在里面不会存在迷路的可能。拐个弯找到阿诗玛的化身拍个照抓紧时间往出口赶。阿诗玛的化身石我怎么看也没看出像一个人来,石头背后的故事就不深究了。

大石林
剑锋池
小石林
小石林
小石林
阿诗玛化身

从石林归来后,又回到了七彩云南。这次购物的重点已经不再是翡翠,而是黄龙玉。黄龙玉产自云南,发现较晚,因此价格较便宜。我直接走向黄龙玉旁边的土特产超市,从里面买点鲜花饼、当地咖啡、普洱茶等,价格还算亲民,拿回来送朋友是个很不错的选择。

在七彩云南吃过地道的过桥米线后直接入住温泉酒店,跟陪伴我们六天的导游和司机师傅说再见后,在温泉酒店做了个鱼疗后,收拾所有的物品打包准备回温馨的家。


Day 8

8点20的飞机,五点半开始往机场赶。12点左右已经回到了温馨的家。


方向感

我无论到哪里都喜欢找找方向感,看看那是南,我是属于那种第一次到一个地方后只要认错了方向就再也调不过来的那种人。这一周的时间我却几乎没有掉过方向来,以至于到后来干脆就不考虑方向了,管他东西南北,只要能回得了酒店,只要能找到大巴就OK了。

民族

本次行程中的几个城市分属于不同的少数民族,风俗习惯、文化传统和建筑风格各有特点。昆明和楚雄是彝族人居多,大理是白族自治州,丽江是纳西族的聚居地,香格里拉主要是藏族人。最有意思的是,这几个少数名族对男女的称呼各有特色。彝族人对男性称呼为“阿黑哥”,对女性称呼为“阿诗玛”;白族分别称呼为“金花”和“阿鹏”;纳西族分别称呼为“胖金妹”和“胖金哥”;藏族分别称呼为“扎西”和“卓玛”。


本来是计划写成散文的,文笔有限,写着写着就写成记叙文了。要是有足够的文采,绝对可以写出比《从百草园到三味书屋》中需要背诵的片段更优美的文字,可惜不是作家的料,仅能码字而已。

旅游不易,码字更难,且行且珍惜。

有些闲暇时间了解了下酷壳的谜题活动,共10道题,每道题都不是非常简单,我这里参考着攻略做了下。

字符替换题

我编写的C++语言程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <stdio.h>
#include <string.h>

char change(char input)
{
char *after = "abcdefghijklmnopqrstuvwxyz";
char *before = "pvwdgazxubqfsnrhocitlkeymj";
for (int i=0; i<strlen(before); i++)
{
if (before[i] == input)
{
return after[i];
}
}
return input;
}

int main()
{
char *input = "Wxgcg txgcg ui p ixgff, txgcg ui p epm. I gyhgwt mrl lig txg ixgff wrsspnd tr irfkg txui hcrvfgs, nre, hfgpig tcm liunz txg crt13 ra \"ixgff\" tr gntgc ngyt fgkgf.";
char *output = new char[strlen(input) + 1];
for (int i=0; i<strlen(input); i++)
{
output[i] = change(input[i]);
}
output[strlen(input)] = '\0';
printf("%s\n", output);
return 1;
}

好久没有用shell了,又写了个shell版本的解题方法,该问题可能有更简单的shell解决办法,我这里肯定写复杂了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/bin/bash

result=''

function change()
{
result=$1
before='pvwdgazxubqfsnrhocitlkeymj'
after='abcdefghijklmnopqrstuvwxyz'
for ((i=0; i <= ${#before}; i++))
do
if [[ ${before:${i}:1} = ${1} ]]
then
result=${after:${i}:1}
break
fi
done
}

input='Wxgcg txgcg ui p ixgff, txgcg ui p epm. I gyhgwt mrl lig txg ixgff wrsspnd tr irfkg txui hcrvfgs, nre, hfgpig tcm liunz txg crt13 ra "ixgff" tr gntgc ngyt fgkgf.'

output=''
j=0
while [ "$j" -le ${#input} ]
do
change "${input:${j}:1}"
output="${output}${result}"
j=$((j+1))
done
echo ${output}

关于rol13的转码可以采用rot13这个网址来在线转码。

穷举变量题

该题需要不断的请求url来获取最终的网址,我这里写一个shell脚本来穷举。

1
2
3
4
5
6
7
8
#!/bin/bash

res=2014
while [ ${#res} > 0 ]
do
res=`curl -s "http://fun.coolshell.cn/n/${res}"`
echo $res
done

得到答案tree

参考

游戏页面
CoolShell puzzle game 攻略
我也不产生代码 – Coolshell 谜题一游

Eclipse默认提供的主题过于刺眼,自己比较习惯黑色背景色。本文分享下修改Eclipse主题的步骤。我所使用的Eclipse版本为Kepler。相关的说明在插件的网站都有相关说明,本文不再赘述。安装完插件后的效果图如下:

我的Eclipse效果图

安装Eclipse Color Theme插件

该插件仅会更新编辑栏中的背景颜色和字体颜色等信息,不会修改Eclipse的整体主题颜色。该插件网址为:https://github.com/eclipse-color-theme/eclipse-color-theme。

安装Eclipse UI Themes主题

该插件会更新除编辑栏之外的其他Eclipse背景色等信息,其Github地址为:http://eclipsecolorthemes.org/。

相关下载

为了方便使用,我这里备份了插件放在百度网盘共享,相关插件下载地址:http://pan.baidu.com/s/1eQnDI86

[TOC]

本文研究了Linux下的一些网卡调优,用于提升网卡的性能。

下文中的所有关于网络的参数可以在/etc/sysctl.conf文件中修改,如果没有相应的参数,可以添加。

查看相应参数在当前运行机器的值可以通过/proc/sys/net/目录下的文件内容查看,也可以对该目录下相应文件的值进行修改,但是由于/proc目录下的文件全部位于内存中,修改的值不会保存到下次开机时。因此要修改参数的值可以通过修改/etc/sysctl.conf文件来完成。

还可以通过sysctl -a命令来查看所有的系统配置参数。

IP协议相关参数配置

  • net.ipv4.ip_default_ttl:设置从本机发出的ip包的生存时间,参数值为整数,范围为0~128,缺省值为64。如果系统经常得到“Time to live exceeded”的icmp回应,可以适当增大该参数的值,但是也不能过大,因为如果你的路由的环路的话,就会增加系统报错的时间。

TCP协议相关参数配置

TCP链接是有很多开销的,一个是会占用文件描述符,另一个是会开缓存,一般来说一个系统可以支持的TCP链接数是有限的。

TCP常规参数

  • /proc/sys/net/ipv4/tcp_window_scaling:设置tcp/ip会话的滑动窗口大小是否可变。参数值为布尔值,为1时表示可变,为0时表示不可变。Tcp/ip 通常使用的窗口最大可达到65535字节,对于高速网络,该值可能太小,这时候如果启用了该功能,可以使tcp/ip滑动窗口大小增大数个数量级,从而提高数据传输的能力。

  • net.core.rmem_default:默认的接收窗口大小。

  • net.core.rmem_max:接收窗口的最大大小。

  • net.core.wmem_default:默认的发送窗口大小。

  • net.core.wmem_max:发送窗口的最大大小。

  • /proc/sys/net/core/wmem_max。最大的TCP发送数据缓冲区大小。

  • /proc/sys/net/ipv4/tcp_timestamps。时间戳在(请参考RFC 1323)TCP的包头增加10个字节,以一种比重发超时更精确的方法(请参阅 RFC 1323)来启用对 RTT 的计算;为了实现更好的性能应该启用这个选项。

配置KeepAlive参数

这个参数的意思是定义一个时间,如果链接上没有数据传输,系统会在这个时间发一个包,如果没有收到回应,那么TCP就认为链接断了,然后就会把链接关闭,这样可以回收系统资源开销。(注:HTTP层上也有KeepAlive参数)对于像HTTP这样的短链接,设置一个1-2分钟的keepalive非常重要。

  • net.ipv4.tcp_keepalive_time:当keepalive打开的情况下,TCP发送keepalive消息的频率。缺省值为7200,即两小时,建议将其更改为1800。

  • net.ipv4.tcp_keepalive_probes:TCP发送keepalive探测以确定该连接已经断开的次数。(默认值是9,设置为5比较合适)。

  • net.ipv4.tcp_keepalive_intvl:探测消息发送的频率,乘以tcp_keepalive_probes就得到对于从开始探测以来没有响应的连接杀除的时间。(默认值为75秒,推荐设为15秒)

配置建立连接参数

  • /proc/sys/net/ipv4/tcp_syn_retries:设置开始建立一个tcp会话时,重试发送syn连接请求包的次数。参数值为小于255的整数,缺省值为10。假如你的连接速度很快,可以考虑降低该值来提高系统响应时间,即便对连接速度很慢的用户,缺省值的设定也足够大了。

  • net.ipv4.tcp_retries1:建立一个连接的最大重试次数,默认为3,不建议修改。

配置关闭连接参数

主动关闭的一方进入TIME_WAIT状态,TIME_WAIT状态将持续2个MSL(Max Segment Lifetime),默认为4分钟,TIME_WAIT状态下的资源不能回收。有大量的TIME_WAIT链接的情况一般是在HTTP服务器上。

  • net.ipv4.tcp_retries2:普通数据的重传次数,在丢弃激活(已建立通讯状况)的TCP连接之前﹐需要进行多少次重试。默认值为15,根据RTO的值来决定,相当于13-30分钟(RFC1122规定,必须大于100秒)。

  • net.ipv4.tcp_tw_reuse:该文件表示是否允许重新应用处于TIME-WAIT状态的socket用于新的TCP连接。可以将其设置为1

  • net.ipv4.tcp_tw_recycle:打开快速TIME-WAIT sockets回收。默认关闭,建议打开。

  • net.ipv4.tcp_fin_timeout:在一个tcp会话过程中,在会话结束时,A首先向B发送一个fin包,在获得B的ack确认包后,A就进入FIN WAIT2状态等待B的fin包然后给B发ack确认包。这个参数就是用来设置A进入FIN WAIT2状态等待对方fin包的超时时间。如果时间到了仍未收到对方的fin包就主动释放该会话。参数值为整数,单位为秒,缺省为180秒,建议设置成30秒。

网卡的参数设置

调整网卡的txqueuelen

txqueuelen的涵义为网卡的发送队列长度,可以通过ifconfig命令找到网卡的txqueuelen参数配置,默认为1000,建议将其更改为5000。

网卡的中断设置

网卡的读写是通过硬件的中断机制来实现的,默认网卡是中断在cpu的内核0上。CPU0非常重要,CPU0具有调整功能,如果CPU0利用率过高,其他cpu核心的利用率也会下降。因此可以考虑将linux的网卡中断绑定到其他的cpu内核上。

可以通过/proc/interrupt文件内容来查看网卡在cpu核的中断情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
           CPU0       CPU1       CPU2       CPU3       
0: 16 0 0 0 IO-APIC-edge timer
1: 17144 2552 2312 2011 IO-APIC-edge i8042
5: 0 0 0 0 IO-APIC-edge parport0
8: 1 0 0 0 IO-APIC-edge rtc0
9: 0 0 0 0 IO-APIC-fasteoi acpi
19: 75011 144479 28826 16212 IO-APIC-fasteoi ata_piix, ata_piix
23: 214627 1 0 2 IO-APIC-fasteoi ehci_hcd:usb1, ehci_hcd:usb2
41: 0 0 0 0 PCI-MSI-edge xhci_hcd
42: 245675 11 17 6 PCI-MSI-edge eth0
43: 18 6 0 0 PCI-MSI-edge mei
44: 423481 80408 67559 54037 PCI-MSI-edge i915
45: 268 488 112 16 PCI-MSI-edge snd_hda_intel
NMI: 21 18 23 18 Non-maskable interrupts
LOC: 7076902 6761203 8711912 9042018 Local timer interrupts
SPU: 0 0 0 0 Spurious interrupts
PMI: 21 18 23 18 Performance monitoring interrupts
IWI: 0 0 0 0 IRQ work interrupts
RTR: 2 0 0 0 APIC ICR read retries
RES: 365564 155654 52242 40754 Rescheduling interrupts
CAL: 12775 15182 23713 23003 Function call interrupts
TLB: 31028 26721 21584 25548 TLB shootdowns
TRM: 0 0 0 0 Thermal event interrupts
THR: 0 0 0 0 Threshold APIC interrupts
MCE: 0 0 0 0 Machine check exceptions
MCP: 32 32 32 32 Machine check polls
ERR: 0
MIS: 0

可以看到eth0的中断是在CPU0上,可以通过/proc/irq/42/smp_affinity文件查看eth0默认的中断分配情况,文件的内容为1,对应二进制为0001,对应的为CPU0。

要想修改中断分配方式,需要先停掉IRQ自动调节的服务进程。

1
2
/etc/init.d/irqbalance stop
echo "2" > /proc/irq/42/smp_affinity

这里的2表示将中断分配到CPU1上。

双网卡负载均衡

两个网卡共用一个IP地址,中断用两个核,效率可以提升一倍。

服务器的其他设置

修改服务器启动级别

可以通过runlevel命令查看机器的启动级别,带图形界面的启动级别为5。可以通过init 3来切换到启动级别3;可以修改/etc/inittab文件中id:5:initdefault:来修改默认级别。

修改系统的文件描述符数

如果网络链接较多,可以修改每个进程打开的最大文件描述符数目,默认为1024.可以通过ulimit -a查看,可以通过ulimit -n 32768来修改。

参考网页

我的大部分读书时间都花在了技术类书籍上,对于扯淡类和鸡汤类的书籍不是我的最爱。本书受到了很多互联网从业人员的推荐,对于技术人员推荐的书籍感觉还是比较靠谱的,因此试着一读,读完之后果然收获颇多。吴军博士的很多观点都相当理性,很多对未来的预测也都在今天得以验证了。文章行为流畅,观点鲜明,能够窥见作者的写作功底。文中的一些观点非常值得记录和学习,本文主要是记录文中观点的摘要,并体现部分自己的理解。

计算机行业发展规律

摩尔定律

摩尔定律:每18个月,计算机等IT产品的性能会翻一番,或者说相同性能的计算机等IT产品,每18个月价钱会降一半。

摩尔定律对行业发展的影响主要体现在以下几个方面:

  1. IT公司必须在比较短的时间内完成下一代产品的开发。天下武功唯快不破,在互联网行业特别合适。
  2. 由于有了强有力的硬件支持,以前都不敢想的应用会不断涌现。手机行业正在深受摩尔定律的影响。
  3. 各个公司现在的研发必须针对多年后的市场。不知道google是否在研究PC版的操作系统来取代Windows了,不知道苹果公司内部是否在研究iphone10了?

安迪-比尔定律

安迪-比尔定律:即比尔要拿走安迪所给的。安迪是原英特尔公司 CEO 安迪·格鲁夫(Andy Grove),比尔就是微软的创始人比尔·盖茨。在过去的二十年里,英特尔处理器的速度每十八个月翻一番,计算机内存和硬盘的容量以更快的速度在增长。但是,微软的操作系统等应用软件越来越慢,也越做越大。所以,现在的计算机虽然比十年前快了一百倍,运行软件感觉上还是和以前差不多。而且,过去整个视窗操作系统不过十几兆大小,现在要几千兆,应用软件也是如此。虽然新的软件功能比以前的版本强了一些,但是,增加的功能绝对不是和它的大小成比例的。因此,一台十年前的计算机能装多少应用程序,现在的也不过装这么多,虽然硬盘的容量增加了一千倍。更糟糕的是,用户发现,如果不更新计算机,现在很多新的软件就用不了,连上网也是个问题。而十年前买得起的车却照样可以跑。

安迪-比尔定律把原本属于耐用消费品的电脑、手机等商品变成了消费性商品,刺激着整个IT领域的发展。

反摩尔定律

反摩尔定律:Google的前CEO埃里克·施密特提出:如果你反过来看摩尔定律,一个IT公司如果今天和18个月前卖掉同样多的、同样的产品,它的营业额就要降一半。IT界把它称为反摩尔定律。反摩尔定理对于所有的IT 公司来讲,都是非常可悲的,因为一个IT
公司花了同样的劳动,却只得到以前一半的收入。反摩尔定理逼着所有的硬件设备公司必须赶上摩尔定理规定的更新速度。

信息产业的规律性

70-20-10定律

当某个领域发展成熟后(而不是群雄争霸时期),一般在全球容不下三个以上的主要竞争者。这个行业一定有一个老大,斯库利把它比喻成一个猴王,它是这个行业的主导者。毫无疑问,它虽然想顺顺当当地统领好整个行业,就像猴王想让猴子们永远臣服一样,但是,它一定会遇到一两个主要的挑战者,也就是老二(也许还有一个老三)。剩下来的是一大群小商家,就像一大群猴子。老大是这个领域的主导者,不仅占据着超过一半,通常是百分之六七十的市场,并且制定了这个领域的游戏规则。老二有自己稳定的百分之二三十的市场份额,有时也会挑战老大并给老大一些颜色看看,但是总的来讲是受老大欺负的时间多。剩下的一群小猴子数量虽然多,但是却只能占到百分之十甚至更少的市场,它们基本上唯老大马首是瞻。老大总是密切注视着老二,并时不时地打压它,防止它做大。老大和老二通常都不会太在意剩下的小企业,这样就让这一群小的企业能有挣一些小钱的地方。

诺维格定律

谷歌研究院院长彼得.诺威格博士说,当一个公司的市场占有率超过50% 以后,就不要
再指望在市场占有率上翻番了。

基因决定定律

一个在某个领域特别成功的大公司一定已经被优化得非常适应这个市场,它的文化、做事方式、商业模式、市场定位等等已经非常适应,甚至过分适应自己传统的市场。这使得该公司获得成功的内在因素会渐渐地、深深地植入该公司,可以讲是这个公司的基因。

基因对于一个公司非常的重要,会影响到公司的整个发展历程。济南的软件公司都是些传统行业的软件公司,在过去十年的时间中发展还算可以。因为行业软件是销售为王,只要销售搞的好,只要不是特别烂的技术都能混过去。现在随着互联网的兴起,很多企业开始转型搞互联网应用,却没有一家搞的起来,到现在济南都没有一家真正意义上的互联网公司,如果有请你告诉我。这些从本质上来说还是基因决定定律的影响。

最佳商业模式

Google的广告系统

在这台印钞机里,运营的成本就是数据中心的费用和带宽的费用,而间接的成本则是打
造和改进这个印钞机的研发费用。在这台印钞机中,自动化程度必须到达一个阈值,它才能自动运转起来。而当它的自动化越高,成本就越低。

Ebay 和亚马逊的在线市场

提供在线交易和支付平台,买卖双方自由交易,赚取手续费用和少量提成。中国的淘宝也基本属于这种模式。

戴尔的虚拟工厂

一个传统的制造业需要通过产品设计、原料采购、仓储运输、加工制造、订单处理、批
发经营和零售七个环节才能收回投资、获得利润。戴尔将上述七个环节减少到两个,仅留订单处理和零售。

腾讯的虚拟物品和服务

销售虚拟商品商业模式必须解决好两个问题:虚拟商品的使用价值和虚拟社交网站中的用户不但是虚拟商品的消费者,还是它们的创造者。解决好上述两个问题,只要累计起足够多的用户基数,虚拟商品就成了社交网站的印钞机。

下一个Google

微软是一家软件公司,百度是一家区域性的互联网公司,而Google更多地是一家科技公司。

下一个Google不可能是搜索公司,而且不太可能是现在意义上依靠广告挣钱的互联网公司,因为这个互联网广告产业不够养活一个像Google这么大的公司。

替代能源和电池在近期很难诞生一个Google这样的公司。

生物和医疗技术有全社会的需求,但是创新周期特别长,加上法律上的风险,不可能在短期内核诞生下一个Google。

在中国和一些亚洲国家,电子商务的潜力可以早就出Google这样的大型新型公司。

如果通过云计算诞生一两个千亿美元的公司,首先会是Google自己,其次是控制开发平台的Facebook,而不会是新面孔。

相关下载

非常精美的读书笔记PPT

在Linux下会父进程通过fork()出的子进程可能会由于某种原因死锁或睡眠而无法终止,这时候需要父进程杀死子进程。本程序是父进程检测到子进程运行一段时间后杀死子进程的例子。

父进程的检测代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <stdio.h>

#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(int argc, char *argv[])
{
int pid = fork();
if (pid > 0)
{
// parent process
int count = 0;
while (1)
{
pid_t result = waitpid(pid, NULL, WNOHANG);
if (result == 0)
{
printf("child process is running\n");
count++;
if (count >= 60 * 60) // one hour
{
kill(pid, 9); // kill child process
}
}
else if (result == pid)
{
printf("child process has exit\n");
break;
}
else
{
printf("result=%d\n", result);
}
sleep(1);
}
}
else if (pid == 0)
{
// child process
execv("/home/kuring/source/child", NULL);
_exit(1);
}
else
{
printf("fork() error\n");
return -1;
}
return 0;
}

子进程调用execv()函数执行的child代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>

#include <unistd.h>

int main(int argc, char *argv[])
{
while (1)
{
sleep(1);
}
return 1;
}

例子比较简单,不作过多解释。

0%