-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
1453 lines (1332 loc) · 79.9 KB
/
atom.xml
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title><![CDATA[张弦的博客]]></title>
<link href="/atom.xml" rel="self"/>
<link href="http://zhangxian.me/"/>
<updated>2014-11-29T09:17:24.984Z</updated>
<id>http://zhangxian.me/</id>
<author>
<name><![CDATA[xuangong]]></name>
<email><![CDATA[[email protected]]]></email>
</author>
<generator uri="http://zespia.tw/hexo/">Hexo</generator>
<entry>
<title><![CDATA[Mac连接win8.1 Remote Desktop Connection问题修复]]></title>
<link href="http://zhangxian.me/2014/11/29/mac-connect-to-win81-via-remote-desktop-connection/"/>
<id>http://zhangxian.me/2014/11/29/mac-connect-to-win81-via-remote-desktop-connection/</id>
<published>2014-11-29T08:44:58.000Z</published>
<updated>2014-11-29T09:17:20.000Z</updated>
<content type="html"><![CDATA[<blockquote>
<p>"Remote Desktop Connection cannot verify the identity of the computer that you want to connect to."</p>
</blockquote>
<p>不过是windows升级到8.1,Mac端Remote Desktop Connection就没法成功远程windows桌面,连接时提示个这,影响生活啊!</p>
<h1 id="-">软件和系统版本:</h1>
<ul>
<li>windows8.1</li>
<li>Yomemite</li>
<li>Remote Desktop Connection软件版本2.1.1</li>
</ul>
<p>用其他的设备比如win7,远程桌面链接我的win8.1是OK的,windows的防火墙已经关掉了,有两种可能:</p>
<ol>
<li>我的client端RDC软件出问题了,但是我用这个软件可以直接远程桌面win7的系统</li>
<li>在防火墙关掉的情况下,win8.1还是把RDC的远程桌面请求给拒绝了,也就是报错信息说的感觉。</li>
</ol>
<p>找了半天终于翻出别人的一个靠谱解决方法,点击<a href="https://social.technet.microsoft.com/Forums/windows/en-US/0b865c92-5e0b-4518-9092-790aed895f5b/remote-desktop-connection-for-mac-os-x-cannot-connect-to-windows-81" target="_blank">这里</a>查看原帖。</p>
<p>我的windows是中文系统,下面把方法说明一下方便遇到问题的windows中文系统的同学们查看。</p>
<h1 id="-">修复方法</h1>
<ol>
<li>首先要保证防火墙是可以允许RDP连接的。<del>我极端的关掉它这种做法不推荐</del></li>
<li>打开控制台,<strong>mmc.exe</strong></li>
<li>点击<code>文件</code>-><code>添加或删除管理单元</code>,在可用的管理单元中选择<code>本地计算机策略</code>后添加;此时看到<code>根目录控制台</code>下出现了<code>本地计算机策略</code></li>
<li>点击<code>本地计算机策略</code>-><code>计算机配置</code>-><code>管理模板</code>-><code>windows组件</code>-><code>远程桌面服务</code>-><code>远程桌面会话主机</code>-><code>安全</code></li>
<li>这个目录下的所有项初始都是<strong>未配置</strong>,有两项需要改变:<ul>
<li><code>远程(RDP)连接要求使用指定的安全层</code>,改成<strong>已启用</strong></li>
<li><code>要求使用网络级别的身份验证对远程连接的用户进行身份验证</code>,改成<strong>已禁用</strong></li>
</ul>
</li>
</ol>
<p>打完这套组合拳,重启下远程桌面连接的服务就好了:
<code>右击 计算机</code>-><code>管理</code>-><code>服务和应用程序</code>-><code>服务</code>,找到<strong>Remote Desktop Services</strong>右击->重新启动</p>
<h1 id="-">舒口气</h1>
<p>现在Mac用可以用Remote Desktop Connection连接上windows8.1了,丝般使用感受又回来了。</p>
]]></content>
<summary type="html">
<![CDATA[<blockquote>
<p>"Remote Desktop Connection cannot verify the identity of the computer that you want to connect to."</p>
</blockquo]]>
</summary>
<category term="tools" scheme="http://zhangxian.me/tags/tools/"/>
</entry>
<entry>
<title><![CDATA[升级到Yosemite之后]]></title>
<link href="http://zhangxian.me/2014/10/19/update-to-yosemite/"/>
<id>http://zhangxian.me/2014/10/19/update-to-yosemite/</id>
<published>2014-10-19T07:55:42.000Z</published>
<updated>2014-10-30T08:32:33.000Z</updated>
<content type="html"><![CDATA[<p>Yosemite正式版发布以后,升级断断续续花了两天,记录一下升级的问题和注意事项:</p>
<h2 id="-">备份</h2>
<p>备份不一定可以找一个移动硬盘,Time Machine可以选择备份哪些资料,比如Downloads这种巨大又没太大用的目录就不要备份了,占硬盘还慢。</p>
<h2 id="-">安装完成</h2>
<p>没来及享受新系统带来的欣喜,发现问题了:</p>
<ol>
<li>brew出问题了,运行brew运行出错<ul>
<li><code>» mv /usr/local/Cellar /tmp/</code></li>
<li><code>» ruby -e "$(curl -fsSL https://raw.github.com/mxcl/homebrew/go/install)"</code>重新安装homebrew</li>
<li><code>» brew update</code></li>
<li><code>» brew doctor</code>根据提示修复环境</li>
<li><code>» brew upgrade</code></li>
</ul>
</li>
<li>brew upgrade时vim报错</li>
<li>brew upgrade时subversion报错</li>
<li>brew upgrade时php55报错<ul>
<li>因为执行<code>brew doctor</code>之后建议我安装xcode6.1,我没有理会导致前面三个东东编译失败。</li>
<li>App Store里是找不到xcode6.1的,需要到这里找<a href="https://developer.apple.com/downloads/index.action" target="_blank">传送门</a>,有2.5G之巨</li>
<li>安装xcode后, 安装xcode命令行工具,<code>xcode-select install && brew upgrade</code>就妥了</li>
</ul>
</li>
<li><code>java -version</code>提示更新java,更新就是了。</li>
</ol>
<h2 id="-">设置出错</h2>
<h3 id="-apache-apache-virtual-host-">因为apache是系统自带的,这回顺便也把apache给我干掉了,配好的virtual host也不行了。</h3>
<p>检查了virtual host的端口已经启来了,document root的读写权限apache的User(_www)也都有。</p>
<p>解决办法:<code>vi /etc/apache2/extra/httpd-vhosts.conf</code></p>
<figure class="highlight"><table><tr><td class="gutter"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
</pre></td><td class="code"><pre><span class="keyword">NameVirtualHost</span> *:8070
<span class="tag"><VirtualHost *:8070></span>
<span class="keyword">ServerAdmin</span> reallocvoid.com
<span class="keyword"><span class="common">DocumentRoot</span></span> <span class="string">"/Users/zhangxian/darwin"</span>
<span class="keyword"><span class="common">ServerName</span></span> localhost
<span class="keyword">ServerAlias</span> reallocvoid.com
<span class="keyword">ErrorLog</span> <span class="string">"/tmp/log/apache2/darwin-error_log"</span>
<span class="keyword">CustomLog</span> <span class="string">"/tmp/log/apache2/darwin-access_log"</span> common
<span class="tag"><Directory "/Users/zhangxian/darwin"></span>
<span class="keyword"><span class="common">Options</span></span> Indexes FollowSymLinks MultiViews
<span class="keyword">AllowOverride</span> <span class="literal">All</span>
<span class="keyword"><span class="common">Order</span></span> allow,deny
<span class="keyword"><span class="common">Allow</span></span> from <span class="literal">all</span>
<span class="comment">#############下方高能,罪魁祸首#############</span>
<span class="comment"># This sentence is needed when update to Yosemite</span>
<span class="keyword">Require</span> <span class="literal">all</span> granted
<span class="tag"></Directory></span>
<span class="tag"></VirtualHost></span>
</pre></td></tr></table></figure>
<h3 id="-apache-extension-">到apache的配置文件重新更改extension的路径:</h3>
<ul>
<li><code>» LoadModule php5_module /usr/local/Cellar/php55/5.5.18/libexec/apache2/libphp5.so</code></li>
<li><code>» sudo apachectl restart</code></li>
</ul>
<h3 id="spotlight">Spotlight</h3>
<p>到偏好设置里把Bing Web Searches和Spotlight Suggestions速度关掉,每次用它还偷偷告诉水果和巨硬我的隐私,<strong>你妹啊</strong>!</p>
<h3 id="-">提示一下小技巧</h3>
<ul>
<li>更改环境变量<code>export PATH=/usr/local/bin:$HOME/bin:$PATH</code>(注意顺序)</li>
<li>如果使用phpstorm,在设置里面搜subversion,用命令行checkout以后再从已经存在的目录新建工程,就会svn报错,估计是svn使用的格式版本不对吧,把工程删掉用phpstorm的svn重新checkout一遍即可。</li>
</ul>
<h3 id="enjoy">Enjoy</h3>
<ul>
<li>手机升级到ios8以后,手机和电脑在一个局域网中就可以实现在电脑上接电话,也可以让手机连接电脑分享出来的热点。<del>我决不抱怨屌丝北邮上网终端限制太蛋疼</del></li>
<li>handoff,只要手机和电脑蓝牙连接起来,就可以实现了,现在只有apple自家的程序支持,我的Wunderlist? Day one? Skype? QQ? We chat? 他们还需要时间。</li>
<li>大赞升级以后iterm2全屏的改变,热键把iterm2切出来的时候干嘛每次要那么多过场动画,就现在这样在当前的space全屏多nice,喜欢透明背景的童鞋还能装装B。</li>
<li>ParallelDesktop 9是不能用的,需要升级到Desktop 10。</li>
<li>看起来比原来要舒服,过去会偶尔无法进入MissionControl界面,现在改善了,而且切换space比原来反应快。</li>
<li>新的通知栏和Safari的改进,确实很棒,解决了蛋疼的问题,谁用谁知道。</li>
</ul>
]]></content>
<summary type="html">
<![CDATA[<p>Yosemite正式版发布以后,升级断断续续花了两天,记录一下升级的问题和注意事项:</p>
<h2 id="-">备份</h2>
<p>备份不一定可以找一个移动硬盘,Time Machine可以选择备份哪些资料,比如Downloads这种巨大又没太大用的目录就不要备份了,]]>
</summary>
<category term="tools" scheme="http://zhangxian.me/tags/tools/"/>
</entry>
<entry>
<title><![CDATA[模拟smtp协议]]></title>
<link href="http://zhangxian.me/2014/07/09/simulate-smtp/"/>
<id>http://zhangxian.me/2014/07/09/simulate-smtp/</id>
<published>2014-07-09T02:41:19.000Z</published>
<updated>2014-10-18T06:50:37.000Z</updated>
<content type="html"><![CDATA[<p>动手写邮件发送的程序之前,第一步让我们来模拟一下smtp协议的过程来发送一份邮件。</p>
<p>下面简单演示一下如何用telnet来模拟smtp协议发送一份邮件</p>
<ol>
<li>找到一个可用的smtp server的ip地址,当前我得到的163邮箱的smtp server的ip地址是220.181.12.16</li>
<li>telnet和smtp server的25端口建立tcp连接,<code>telnet 220.181.12.16 25</code>,收到的回应是"220 163.com Anti-spam GT for Coremail System (163com[20121016])"</li>
<li>发送<code>HELO 220.181.12.16</code>,收到回应"250 OK"</li>
<li>请求登录,发送<code>auth login</code>,收到回应“334 dXNlcm5hbWU6”,后面那串字母是被base64加密后的内容,解密后的实际内容是:"username:"</li>
<li>发送自己163邮箱的用户名base64加密后的内容,比如我的email地址是"[email protected]",我的username就是"zhang_xian_freedom",所以我发送的内容是:<code>emhhbmdfeGlhbl9mcmVlZG9t</code>。收到回应:334 UGFzc3dvcmQ6",解密后的实际内容是:"Password:"</li>
<li>发送自己用户名对应的密码用base64加密后的内容,收到回应:"235 Authentication successful"。到此,跟mail server身份验证的工作已经结束。</li>
<li>跟smpt服务器指定邮件的来处:<code>mail from:<[email protected]></code>,收到回应:"250 Mail OK"</li>
<li>跟smpt服务器指定要发送的邮件去处:<code>rcpt to:<[email protected]></code>,收到回应:"250 Mail OK"</li>
<li>发送邮件正文内容标识:<code>data</code>,收到回应:<code>354 End data with <CR><LF>.<CR><LF></code></li>
<li>邮件中显示的发给谁:<code>to:[email protected]</code>和<code>subject:Test Mail</code></li>
<li>发送一个空行,然后发送邮件正文<code>This is a test mail...</code></li>
<li>发送<code>.</code>标识结束<a id="more"></a>
</li>
</ol>
<p><img src="/images/20140709.smtp.simulate.png" alt="命令行交互过程"></p>
<p><img src="/images/20140709.mail.list.png" alt="邮件"></p>
<p>BTW,mac中善用alfred的workflow,我用<a href="https://github.com/BigLuck/alfred2-hash" target="_blank">Hash calculator</a>可以很方便的做Base64 Encode和Base64 Decode。</p>
]]></content>
<summary type="html">
<![CDATA[<p>动手写邮件发送的程序之前,第一步让我们来模拟一下smtp协议的过程来发送一份邮件。</p>
<p>下面简单演示一下如何用telnet来模拟smtp协议发送一份邮件</p>
<ol>
<li>找到一个可用的smtp server的ip地址,当前我得到的163邮箱的smtp server的ip地址是220.181.12.16</li>
<li>telnet和smtp server的25端口建立tcp连接,<code>telnet 220.181.12.16 25</code>,收到的回应是"220 163.com Anti-spam GT for Coremail System (163com[20121016])"</li>
<li>发送<code>HELO 220.181.12.16</code>,收到回应"250 OK"</li>
<li>请求登录,发送<code>auth login</code>,收到回应“334 dXNlcm5hbWU6”,后面那串字母是被base64加密后的内容,解密后的实际内容是:"username:"</li>
<li>发送自己163邮箱的用户名base64加密后的内容,比如我的email地址是"[email protected]",我的username就是"zhang_xian_freedom",所以我发送的内容是:<code>emhhbmdfeGlhbl9mcmVlZG9t</code>。收到回应:334 UGFzc3dvcmQ6",解密后的实际内容是:"Password:"</li>
<li>发送自己用户名对应的密码用base64加密后的内容,收到回应:"235 Authentication successful"。到此,跟mail server身份验证的工作已经结束。</li>
<li>跟smpt服务器指定邮件的来处:<code>mail from:<[email protected]></code>,收到回应:"250 Mail OK"</li>
<li>跟smpt服务器指定要发送的邮件去处:<code>rcpt to:<[email protected]></code>,收到回应:"250 Mail OK"</li>
<li>发送邮件正文内容标识:<code>data</code>,收到回应:<code>354 End data with <CR><LF>.<CR><LF></code></li>
<li>邮件中显示的发给谁:<code>to:[email protected]</code>和<code>subject:Test Mail</code></li>
<li>发送一个空行,然后发送邮件正文<code>This is a test mail...</code></li>
<li>发送<code>.</code>标识结束]]>
</summary>
<category term="protocol" scheme="http://zhangxian.me/tags/protocol/"/>
</entry>
<entry>
<title><![CDATA[理解跳跃表skiplist]]></title>
<link href="http://zhangxian.me/2014/07/01/skiplist/"/>
<id>http://zhangxian.me/2014/07/01/skiplist/</id>
<published>2014-06-30T16:53:43.000Z</published>
<updated>2014-10-18T06:50:37.000Z</updated>
<content type="html"><![CDATA[<blockquote>
<p>跳跃表是一种随机化数据结构,基于<strong>并联的链表</strong>,其效率可以逼近二叉查找树,对于大多数操作需要O(logn)平均时间,并且对<strong>并发</strong>算法友好。
跳跃表对<strong>有序</strong>链表增加附加的前进链接,增加(Insert)是以随机化的方式进行的,所以可以快速的跳过部分列表,故以此得名。
她是很年轻的算法而且实现简单,深受广大程序员喜爱。</p>
</blockquote>
<p>需要动态维护数据,有对数复杂度的插入、删除和查找性能,可以选择的数据结构很多,比如:</p>
<ul>
<li>B-tree</li>
<li>Red-black tree</li>
<li>treap</li>
</ul>
<p>如果要求一个小时完成程序,竟然还不给我们翻书,那咱们选择谁呢?OK,答案是我们今天的主人公:跳跃表skiplist</p>
<p>跳跃表按层构造的,让我们看一下redis中跳跃表的数据结构(<a href="http://github.com/antirez/redis/blob/unstable/src/redis.h" target="_blank">redis.h</a>):
<a id="more"></a></p>
<figure class="highlight c"><table><tr><td class="gutter"><pre>1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="code"><pre><span class="comment">/*
* 跳跃表
*/</span>
<span class="keyword">typedef</span> <span class="keyword">struct</span> zskiplist {
<span class="comment">// 头节点,尾节点</span>
<span class="keyword">struct</span> zskiplistNode *header, *tail;
<span class="comment">// 节点数量</span>
<span class="keyword">unsigned</span> <span class="keyword">long</span> length;
<span class="comment">// 目前表内节点的最大层数</span>
<span class="keyword">int</span> level;
} zskiplist;
</pre></td></tr></table></figure>
<p>而zskiplistNode的数据结构如下:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="code"><pre><span class="comment">/* ZSETs use a specialized version of Skiplists */</span>
<span class="comment">/*
* 跳跃表节点
*/</span>
<span class="keyword">typedef</span> <span class="keyword">struct</span> zskiplistNode {
<span class="comment">// member 对象</span>
robj *obj;
<span class="comment">// 分值</span>
<span class="keyword">double</span> score;
<span class="comment">// 后退指针</span>
<span class="keyword">struct</span> zskiplistNode *backward;
<span class="comment">// 层</span>
<span class="keyword">struct</span> zskiplistLevel {
<span class="comment">// 前进指针</span>
<span class="keyword">struct</span> zskiplistNode *forward;
<span class="comment">// 这个层跨越的节点数量</span>
<span class="keyword">unsigned</span> <span class="keyword">int</span> span;
} level[];
} zskiplistNode;
</pre></td></tr></table></figure>
<p>zslCreate的时候tail直接为空,但是header是需要被创建并初始化为空的。数据结构中需要理解清楚的是span的含义,每个zskiplistNode的不同zskiplistLevel都有其独立的span,标识在这一层上,从该节点跳跃到下一个节点的步长:</p>
<ul>
<li>同一层的不同节点包含的span可以不同</li>
<li>新增一层时span直接初始化为跳表的长度</li>
</ul>
<p>Insert数据时,先给每一层定位插入节点的位置(从高层到低层查找)</p>
<p>跳跃表插入结构如图</p>
<p><img src="http://images.cnblogs.com/cnblogs_com/xuqiang/algorithm/skiplist_delete.png" alt="skiplist" title="insert-skiplist"></p>
<p>核心代码逻辑如下所示(<a href="https://github.com/antirez/redis/blob/unstable/src/t_zset.c" target="_blank">t_zset.c</a>):</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
</pre></td><td class="code"><pre> x = zsl->header;
<span class="comment">// 记录沿途访问的节点,并计数 span 等属性</span>
<span class="comment">// 平均 O(log N) ,最坏 O(N)</span>
<span class="keyword">for</span> (i = zsl->level-<span class="number">1</span>; i >= <span class="number">0</span>; i--) {
<span class="comment">/* store rank that is crossed to reach the insert position */</span>
rank[i] = i == (zsl->level-<span class="number">1</span>) ? <span class="number">0</span> : rank[i+<span class="number">1</span>];
<span class="comment">// 右节点不为空</span>
<span class="keyword">while</span> (x->level[i].forward &&
<span class="comment">// 右节点的 score 比给定 score 小</span>
(x->level[i].forward->score < score ||
<span class="comment">// 右节点的 score 相同,但节点的 member 比输入 member 要小</span>
(x->level[i].forward->score == score &&
compareStringObjects(x->level[i].forward->obj,obj) < <span class="number">0</span>))) {
<span class="comment">// 记录跨越了多少个元素</span>
rank[i] += x->level[i].span;
<span class="comment">// 继续向右前进</span>
x = x->level[i].forward;
}
<span class="comment">// 保存访问节点</span>
update[i] = x;
}
</pre></td></tr></table></figure>
<p>先查找到最高层(最稀疏的层,直到发现右边元素比左边元素大时,记录该Node到update[level-1]),用保存节点的变量node x,定位x的下一层,继续查找。这样就可以用接近二叉查找树的性能找到各层需要插入位置的前邻近节点(第i层保存为update[i]),同时统计出各层预计插入位置前邻近节点已经跨越了多少个实际节点(逻辑上第0层的节点):rank[i](从header后面真正的数据节点开始算)。</p>
<p>用很好的性能做好这样的准备工作以后,就开始真正的插入动作,插入时需要确定在哪一层插入,跳表采用的是随机化方法,插入在第i+1层的概率是出现在i层的1/p决定插入level的算法如下:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre>1
2
3
4
5
6
</pre></td><td class="code"><pre><span class="keyword">int</span> zslRandomLevel(<span class="keyword">void</span>) {
<span class="keyword">int</span> level = <span class="number">1</span>;
<span class="keyword">while</span> ((random()&<span class="number">0xFFFF</span>) < (ZSKIPLIST_P * <span class="number">0xFFFF</span>))
level += <span class="number">1</span>;
<span class="keyword">return</span> (level<ZSKIPLIST_MAXLEVEL) ? level : ZSKIPLIST_MAXLEVEL;
}
</pre></td></tr></table></figure>
<p>需要明确的是,在跳表中,虽然节点的指针很多,但是数据本身不会保存多份(<strong>共享的是一份数据</strong>)
节点中上层level的span是计算出来的(准确的说是由底层的信息计算出来的),计算的方法如下:</p>
<ul>
<li>我们容易得到各层距离插入点最近的节点跨越了多少节点(从header后面真正的数据节点开始算),即rank[i]。</li>
<li>我们知道已存在节点各层span(即节点跳跃到右边一步实际跨越多少个节点)</li>
</ul>
<p>操作有三种情况,假设插入一个节点选择的层是level,操作过程分一下几类情况:</p>
<ol>
<li>(level,zsl->level] 范围内,插入操作是不影响结构的,只需要更新这范围内各层中距离插入几点最近的节点中span的数字: <code>update[i].level[i].span++</code></li>
<li>[0, level] 范围内,插入节点是影响结构的,span的计算是用<code>update[i].level[i].span - (rank[i] - rank[0] ) + 1</code></li>
<li>(zsl->level, level] 范围内,说明这些层还没有被建立起来,这个范围内的各层需要设置<code>rank[i] = 0</code>(看作从header降层下来的)更新<code>update[i].span = zsl->length</code>同时 更新 <code>zsl->level = level</code>,范围就转化成了第2中情况</li>
</ol>
<p>理解跳跃表的核心部分就说完了,捋清楚插入的过程,查找和删除就非常容易了。Enjoy...</p>
]]></content>
<summary type="html">
<![CDATA[<blockquote>
<p>跳跃表是一种随机化数据结构,基于<strong>并联的链表</strong>,其效率可以逼近二叉查找树,对于大多数操作需要O(logn)平均时间,并且对<strong>并发</strong>算法友好。
跳跃表对<strong>有序</strong>链表增加附加的前进链接,增加(Insert)是以随机化的方式进行的,所以可以快速的跳过部分列表,故以此得名。
她是很年轻的算法而且实现简单,深受广大程序员喜爱。</p>
</blockquote>
<p>需要动态维护数据,有对数复杂度的插入、删除和查找性能,可以选择的数据结构很多,比如:</p>
<ul>
<li>B-tree</li>
<li>Red-black tree</li>
<li>treap</li>
</ul>
<p>如果要求一个小时完成程序,竟然还不给我们翻书,那咱们选择谁呢?OK,答案是我们今天的主人公:跳跃表skiplist</p>
<p>跳跃表按层构造的,让我们看一下redis中跳跃表的数据结构(<a href="http://github.com/antirez/redis/blob/unstable/src/redis.h" target="_blank">redis.h</a>):
]]>
</summary>
<category term="algorithm" scheme="http://zhangxian.me/tags/algorithm/"/>
<category term="data structure" scheme="http://zhangxian.me/tags/data%20structure/"/>
</entry>
<entry>
<title><![CDATA[由一道寻找唯一数字的题想到的]]></title>
<link href="http://zhangxian.me/2014/06/28/find-the-special-num/"/>
<id>http://zhangxian.me/2014/06/28/find-the-special-num/</id>
<published>2014-06-27T17:43:59.000Z</published>
<updated>2014-10-18T06:50:37.000Z</updated>
<content type="html"><![CDATA[<p>最近本科室友发消息来问了一道题,引发了我一连串的好奇心。</p>
<p>P.S. 据师兄说这类问题貌似某书上有说过,可是已经不记得了,汗。。只怪肚子里的墨水太少,事实证明我这种庸人就应该事儿多^_^!</p>
<h3 id="1-">1.有很多数字,其中两两一样,只有一个数字不同,找出这个数字?</h3>
<hr>
<p>可以把让每个数字按位异或,最后得到的就是那个数字,这个是很基础的想法。时间复杂度O(n),空间是O(1),not bad.
扩展**
2.如果有两个数字是唯一的,怎么找出这两个数字?</p>
<hr>
<p>处理两遍,第一遍先按位异或,最后肯定得到的是一个不为零的数字,然后按照一个不为零的bit来划分所有的整数,得到两个集合,每个集合都符合<strong>第1题</strong>的情况,分别对两个集合处理,就能找到这两个数字。
继续扩展**
<a id="more"></a>
3.如果有三个数字是唯一的,怎么找出这三个数字?</p>
<p>OK,这个问题还是要转换到之前的问题上去,和第2问一样,我们怎么样才能把这三个数字给分开。
这三个数字是唯一的,其他的数字都是配对的,那我们还是按bit来分类呗。<strong>第2题</strong>先全部异或一遍,来精确找到各个唯一数字之间的差别的方法已经不好用了。(因为三个互异的数字异或完全可以等于0,又不能不异或,要不其他的配对数字就会产生<code>不想要</code>的贡献)
既然不能精确的知道这些唯一的数字到底那地方不通,那就暴力一点吧,咱们就假设可以按照一位来分割,比如<code>the first bit</code>,按照这一位来划分集合,只有两种情况,这三个数字被分割成两个集合,各个集合中包含目标数字个数总共就这么几种情况:<code>1|2、2|1、0|3、3|0</code>。我们需要统计分成的两组的数字个数。</p>
<p>如果分成1个和2个,到此成功把问题转化成了第2问和第1问,O(n)解决战斗。</p>
<p>如果分成0个和3个就讨厌了,问题并没有解决,甚至问题规模都不一定会减小。
咱们怎么来区分出这两种情况呢,不管集合中有1个还是2个<strong>目标数字</strong>,集合中元素异或起来都绝对非0。既然有0个<strong>目标数字</strong>的集合异或必然是0,异或可以解决问题。为了减少计算量,可以在分组的时候提前统计集合元素的数目,对大小为偶数的集合进行异或(为0就是含<strong>目标数字</strong>0个,非0就是含<strong>目标数字</strong>2个),奇数个的元素就自生自灭不管它。</p>
<p>现在我们成功的解决了第一种情况,事情进展的比预想的好一些,0个和3个<strong>目标数字</strong>咋办?问题规模还不一定减少,这。。。
想到这里,需要去喝点东西,45度角仰望天空看看天台上的意大利球迷。终于发现,问题卡壳是思维定势了。</p>
<p>虽然乍看下来,按一位分组,可能问题规模没有减小(分成0个和3个的情况)。。可是题目中说的是3个<strong>目标数字</strong>互异,也就是说不可能每一位都把3个<strong>目标数字</strong>都分到一边,只要把32位都按上面的方法分组过一遍,一定能把<strong>目标数字</strong>分成1个和2个的分组情况。这个复杂度可不是n方,数字的位数是定长的,最多也就32n,问题到此算是圆满解决了。</p>
<p>P.S. 这种方法我并不能推广到更多的目标数字去,如果你有更好的更通用的方法,请留言或者email告知我,邮箱在文章末尾</p>
<p><strong>往另一个方向上扩展</strong></p>
<h3 id="4-">4.如果数字都是三个一组相同,只有一个数字唯一,应该怎么找出这个数字?</h3>
<p>可以统计所有集合中每一位的出现情况,是三的倍数的就不管了,不是三的倍数的就是从<strong>目标数字</strong>中来的,这样用int variable[32]来计数就可以了,这样写没问题。</p>
<p>这个问题其实可以联系到前3个题目上,让我们进一步来寻找这个问题的不变式,联想第1个问题,两两相同的时候,可以按位异或。按位异或就是针对每个bit相同为0,不同为1,用一个整数来记录异或的结果,就是记录每个bit的状态转移,一个bit只要出现的次数是2的倍数就得是0,否则是1,最后就求解成功。</p>
<p>现在的问题是三个一组相同,其实就是每一个bit出现的次数是3的整数倍,就应该是0。很清楚了,尼玛可以想办法来记录0-1-2-0的状态转移啊...怎么表示这个状态转移呢,只需要两位就能表示三个状态了(这里可以扩展),<strong>bingo</strong></p>
<p>我们设置两个整数a和b,其中a和b的第n个bit(共2个bit)就代表了集合中数字第n个bit出现1次数的状态情况(mod 3下:0-1-2-0)。这就是这个问题开头说的不变式,按位来看每一位的状态转移规则是完全相同的,就可以把这些需要处理的位搁在一起放好,组成整数一块计算(32bit)。</p>
<p>代码如下:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="code"><pre><span class="comment">//ones as a bitmask to represent the ith bit had appeared once.</span>
<span class="comment">//twos as a bitmask to represent the ith bit had appeared twice.</span>
<span class="comment">//threes as a bitmask to represent the ith bit had appeared three times.</span>
<span class="keyword">int</span> singleNumber(<span class="keyword">int</span> A[], <span class="keyword">int</span> n) {
<span class="keyword">int</span> ones = <span class="number">0</span>, twos = <span class="number">0</span>, threes = <span class="number">0</span>;
<span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < n; i++) {
twos |= ones & A[i];
ones ^= A[i];
threes = ones & twos;
ones &= ~threes;
twos &= ~threes;
}
<span class="keyword">return</span> ones;
}
</pre></td></tr></table></figure>
<p>上面的代码中真正参加标识状态只需要两个变量,即ones和twos,其中threes是用来标记辅助置0状态的。
可以把这第三个变量优化掉。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre>1
2
3
4
5
6
7
8
9
10
</pre></td><td class="code"><pre><span class="keyword">int</span> singleNumber(<span class="keyword">int</span> A[], <span class="keyword">int</span> n)
{
<span class="keyword">int</span> ones = <span class="number">0</span>, twos = <span class="number">0</span>;
<span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i < n; i++)
{
ones = (ones ^ A[i]) & ~twos;
twos = (twos ^ A[i]) & ~ones;
}
<span class="keyword">return</span> ones;
}
</pre></td></tr></table></figure>
<p><strong>P.S. 仅抛砖引玉,欢迎继续扩展讨论,欢迎发邮件到 <code>[email protected]</code> 告知我,十分感谢^_^!</strong></p>
]]></content>
<summary type="html">
<![CDATA[<p>最近本科室友发消息来问了一道题,引发了我一连串的好奇心。</p>
<p>P.S. 据师兄说这类问题貌似某书上有说过,可是已经不记得了,汗。。只怪肚子里的墨水太少,事实证明我这种庸人就应该事儿多^_^!</p>
<h3 id="1-">1.有很多数字,其中两两一样,只有一个数字不同,找出这个数字?</h3>
<hr>
<p>可以把让每个数字按位异或,最后得到的就是那个数字,这个是很基础的想法。时间复杂度O(n),空间是O(1),not bad.
扩展**
2.如果有两个数字是唯一的,怎么找出这两个数字?</p>
<hr>
<p>处理两遍,第一遍先按位异或,最后肯定得到的是一个不为零的数字,然后按照一个不为零的bit来划分所有的整数,得到两个集合,每个集合都符合<strong>第1题</strong>的情况,分别对两个集合处理,就能找到这两个数字。
继续扩展**
]]>
</summary>
<category term="algorithm" scheme="http://zhangxian.me/tags/algorithm/"/>
</entry>
<entry>
<title><![CDATA[Damn Line End Character]]></title>
<link href="http://zhangxian.me/2014/05/31/damn-line-end-character/"/>
<id>http://zhangxian.me/2014/05/31/damn-line-end-character/</id>
<published>2014-05-30T18:28:15.000Z</published>
<updated>2014-10-18T06:50:37.000Z</updated>
<content type="html"><![CDATA[<p>这是在跨平台编辑代码的时候遇到的蛋疼问题。shell文件从dropbox同步到win上看一看再同步回mac,擦,执行的时候抽风了!</p>
<p>作为一个无知且不天真的低级码农,碰到这个诡异的问题不能忍,搞清楚了记一下。</p>
<p>vim认为win、unix和mac三大平台的换行符都不一样,分别是CRLF、LF和CR。尼玛,这个排列组合能再彻底一点吗?当然这个有历史原因,不过还是要说,尼玛!
<a id="more"></a></p>
<p>不知道为什么,用mac x10.9.3中自带的textEdit编辑以后,其实换行符都是按照unix的方式来的(这么做比较合理,不然cat一个文本什么都不输出,因为木有换行符啊!),所以这两个平台应该统一了,<strong>我们这里说的是VIM怎么看</strong>。</p>
<p>CR显示出来是^M,而LF显示出来是^J。VIM在加载文件到缓冲区的时候,会对文本进行预处理,规则如下:</p>
<figure class="highlight"><table><tr><td class="gutter"><pre>1
2
3
</pre></td><td class="code"><pre>如果all <span class="keyword">lines</span>的换行符是<span class="constant">CRLF</span>,则按照dos的规则处理,把<span class="constant">CRLF</span>都给处理成不可见字符后加载到缓冲区,当前buffer的ff变成dos。
如果有一行换行符是LF,则按照unix换行符的规则处理,把LF都处理成不可见字符后加载到缓冲区,当前buffer的ff变成unix。
这也是我们为什么把win下的文本放在linux中会有那么多的^M(顺便多句嘴,在vim中打出^M是ctrl-v ctrl-M)
</pre></td></tr></table></figure>
<p>强制让文本按照一种规则来加载到当前缓冲区可以<code>:e ++ff=dos[unix/mac]</code>,如果指定为mac,CF显示出来是另起一行显示^J</p>
<p>不可见字符变成了可见字符,就可以编辑了,正则匹配的时候,vim用<code>\r</code>可以把^M或者^J都匹配出来。</p>
<p>vim的默认fileformats=unix,dos,可以用<code>:set ffs</code>查看。如果是CRLF(format为dos)和LF共存的时候,会出现很多讨厌的^M,这个时候<code>:e ++ff=dos</code>后缓冲区的^M都不见了(不是真没了),然后<code>:setlocal ff=unix</code>再保存,于是保存的时候vim按照LF自动加上了换行符,nice!不改ff=unix直接保存是不行的,那样文本就不变了,记住默认的fileformats。</p>
<p>当然纯win下的文件把换行符改成LF,也可以这样干。</p>
<p>当然本来的format=dos,执行<code>:e ++f=unix</code>不可见字符^M显示出来以后,正则去处理,手动删除,随便你虐了。</p>
<p>到此,换行符这个蛋疼的问题算是讲清楚了,收工!</p>
]]></content>
<summary type="html">
<![CDATA[<p>这是在跨平台编辑代码的时候遇到的蛋疼问题。shell文件从dropbox同步到win上看一看再同步回mac,擦,执行的时候抽风了!</p>
<p>作为一个无知且不天真的低级码农,碰到这个诡异的问题不能忍,搞清楚了记一下。</p>
<p>vim认为win、unix和mac三大平台的换行符都不一样,分别是CRLF、LF和CR。尼玛,这个排列组合能再彻底一点吗?当然这个有历史原因,不过还是要说,尼玛!
]]>
</summary>
<category term="linux" scheme="http://zhangxian.me/tags/linux/"/>
</entry>
<entry>
<title><![CDATA[ucc中的奇技淫巧(持续更新)]]></title>
<link href="http://zhangxian.me/2014/05/23/ucc%E4%B8%AD%E7%9A%84%E5%A5%87%E6%8A%80%E6%B7%AB%E5%B7%A7/"/>
<id>http://zhangxian.me/2014/05/23/ucc中的奇技淫巧/</id>
<published>2014-05-22T17:13:10.000Z</published>
<updated>2014-10-18T06:50:37.000Z</updated>
<content type="html"><![CDATA[<h2 id="-ucc-c98-naive-_-">对ucc——代码挺好看的一个c98编译器的naive记录...别瞎折腾,没什么用^_^</h2>
<h3 id="1-enum-">1.初始化寄存器变量的时候,寄存器是用enum类型来表示的:</h3>
<hr>
<p><code>enum { EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI };</code></p>
<p>申明数组大小的时候这么如:<code>Symbol X86Regs[EDI + 1];</code>这样以后要跟新这个列表,只要大小写保持是enum的最后一个就可以了。
<a id="more"></a></p>
<h3 id="2-">2.词法器的初始化:</h3>
<hr>
<p>搞了一个256大小的数组,存储函数指针,是为了直接把字符的ASCII码当成数组下标,256个下标对应的类型分成一下四类:</p>
<pre><code>- 语言中的符号` ' " + - * / % < > = ! | & ^ . { } ( ) [ ] , ; ~ ? : `加上`END_OF_FILE`
- 字母
- 数字
- 其它(不认识的字符,就可以抛出错误了)
</code></pre><p>注意:注意后面三类其实每一类的处理函数是一样的。第一类又可以分为两类:<code>{ } ( ) [ ] , ; ~ ? :</code>处理过程类似,移动读入指针和返回对应的token;其它的处理方式要单独写。</p>
<h3 id="3-">3.静态的组织表格的方法:</h3>
<hr>
<figure class="highlight"><table><tr><td class="gutter"><pre>1
2
3
4
5
6
7
</pre></td><td class="code"><pre><span class="keyword">enum</span> token
{
TK_BEGIN,
<span class="preprocessor">#<span class="keyword">define</span> TOKEN(k, s) k,</span>
<span class="preprocessor">#include "token.h"</span>
<span class="preprocessor">#<span class="keyword">undef</span> TOKEN</span>
};
</pre></td></tr></table></figure>
<p>token.h中截了三行,这样就可以想要取哪列都可以了,很清楚</p>
<figure class="highlight"><table><tr><td class="gutter"><pre>1
2
3
</pre></td><td class="code"><pre><span class="function">TOKEN(TK_VOLATILE, <span class="string">"volatile"</span>)</span>
<span class="function">TOKEN(TK_SIGNED, <span class="string">"signed"</span>)</span>
<span class="function">TOKEN(TK_UNSIGNED, <span class="string">"unsigned"</span>)</span>
</pre></td></tr></table></figure>
<h3 id="4-linux-">4.在处理内存对齐的时候有一个宏很有意思,在linux中常见:</h3>
<hr>
<figure class="highlight"><table><tr><td class="gutter"><pre>1
</pre></td><td class="code"><pre>#define ALIGN(<span class="keyword">size</span>, <span class="keyword">align</span>) ((<span class="keyword">size</span> + <span class="keyword">align</span> - <span class="number">1</span>) & (~(<span class="keyword">align</span> - <span class="number">1</span>)))
</pre></td></tr></table></figure>
<p>记录一下这么搞的原理:<code>ALIGN(size, align)的得到的值,是size按照以align为倍数取上界</code></p>
<p>align如果值是8,则~(align-1)的值就是111...111000,这就是按照倍数取得上下界的关键,可称为对齐掩码。
先看这个式子</p>
<p><code>size & ~(align-1)</code>表示的就是按照align的倍数取<code>下界</code>,这个很容易理解。再想怎么样才能定上界呢?其实有个非常容易想到的做法,就是加上align,但是这么做的bad case就是size本身就正好是align的倍数,这么做就错了,当然可以做判断修正这个bad case,同样也可以利用~(align-1)来修正,就得到了(size + size - 1) & (~(align - 1))</p>
<h3 id="5-ucc-">5.这个技巧不是ucc中看到的,但是值得一说</h3>
<hr>
<ol>
<li><code>#define IS_POWER_OF_2(x) (!((x)&((x)-1)))</code> 只有x是2的幂次的时候,这个表达式才是真</li>
<li>凑2的次幂取size的上界,代码和注释如下<figure class="highlight c"><table><tr><td class="gutter"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="code"><pre><span class="comment">/**
* 把size调整到向上取到最近的2次幂
* size |= size >> n;表示从低位到高位按2n位分组,每组内高n位复制到低n位
* 最后经过处理size是从最高位的1开始往低位全1的整数
* return size + 1; 得到向上凑够最近2次幂
*/</span>
<span class="keyword">static</span> <span class="keyword">unsigned</span> fixsize(<span class="keyword">unsigned</span> size) {
size |= size >> <span class="number">1</span>;
size |= size >> <span class="number">2</span>;
size |= size >> <span class="number">4</span>;
size |= size >> <span class="number">8</span>;
size |= size >> <span class="number">16</span>;
<span class="keyword">return</span> size+<span class="number">1</span>;
}
</pre></td></tr></table></figure>
</li>
</ol>
<h3 id="6-ucc-">6.ucc中内存的管理是维护了一个链表</h3>
<hr>
<p>这个模型非常简单,就是一个单向链表,链表记录了begin,end,avail三个指针,如果不够用了,就再申请大块的内存;够用了就直接从维护的堆上拿。
这样做的好处就是可以一直申请内存不释放,到最后一并把堆释放了就妥妥的。</p>
]]></content>
<summary type="html">
<![CDATA[<h2 id="-ucc-c98-naive-_-">对ucc——代码挺好看的一个c98编译器的naive记录...别瞎折腾,没什么用^_^</h2>
<h3 id="1-enum-">1.初始化寄存器变量的时候,寄存器是用enum类型来表示的:</h3>
<hr>
<p><code>enum { EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI };</code></p>
<p>申明数组大小的时候这么如:<code>Symbol X86Regs[EDI + 1];</code>这样以后要跟新这个列表,只要大小写保持是enum的最后一个就可以了。
]]>
</summary>
<category term="c" scheme="http://zhangxian.me/tags/c/"/>
</entry>
<entry>
<title><![CDATA[常见的字符串Hash算法列举]]></title>
<link href="http://zhangxian.me/2014/05/23/string%20hash%20methods/"/>
<id>http://zhangxian.me/2014/05/23/string hash methods/</id>
<published>2014-05-22T16:00:01.000Z</published>
<updated>2014-10-18T06:50:37.000Z</updated>
<content type="html"><![CDATA[<p>常见的字符串Hash算法如下,ucc中对符号表使用的是ELFHash,查了一下貌似不是效果非常好的hash算法。也列一列常用的hash算法以备不时之需。
<a id="more"></a></p>
<figure class="highlight c"><table><tr><td class="gutter"><pre>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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
</pre></td><td class="code"><pre><span class="keyword">unsigned</span> <span class="keyword">int</span> SDBMHash(<span class="keyword">char</span> *str)
{
<span class="keyword">unsigned</span> <span class="keyword">int</span> hash = <span class="number">0</span>;
<span class="keyword">while</span> (*str)
{
<span class="comment">// equivalent to: hash = 65599*hash + (*str++);</span>
hash = (*str++) + (hash << <span class="number">6</span>) + (hash << <span class="number">16</span>) - hash;
}
<span class="keyword">return</span> (hash & <span class="number">0x7FFFFFFF</span>);
}
<span class="comment">// RS Hash Function</span>
<span class="keyword">unsigned</span> <span class="keyword">int</span> RSHash(<span class="keyword">char</span> *str)
{
<span class="keyword">unsigned</span> <span class="keyword">int</span> b = <span class="number">378551</span>;
<span class="keyword">unsigned</span> <span class="keyword">int</span> a = <span class="number">63689</span>;
<span class="keyword">unsigned</span> <span class="keyword">int</span> hash = <span class="number">0</span>;
<span class="keyword">while</span> (*str)
{
hash = hash * a + (*str++);
a *= b;
}
<span class="keyword">return</span> (hash & <span class="number">0x7FFFFFFF</span>);
}
<span class="comment">// JS Hash Function</span>
<span class="keyword">unsigned</span> <span class="keyword">int</span> JSHash(<span class="keyword">char</span> *str)
{
<span class="keyword">unsigned</span> <span class="keyword">int</span> hash = <span class="number">1315423911</span>;
<span class="keyword">while</span> (*str)
{
hash ^= ((hash << <span class="number">5</span>) + (*str++) + (hash >> <span class="number">2</span>));
}
<span class="keyword">return</span> (hash & <span class="number">0x7FFFFFFF</span>);
}
<span class="comment">// P. J. Weinberger Hash Function</span>
<span class="keyword">unsigned</span> <span class="keyword">int</span> PJWHash(<span class="keyword">char</span> *str)
{
<span class="keyword">unsigned</span> <span class="keyword">int</span> BitsInUnignedInt = (<span class="keyword">unsigned</span> <span class="keyword">int</span>)(<span class="keyword">sizeof</span>(<span class="keyword">unsigned</span> <span class="keyword">int</span>) * <span class="number">8</span>);
<span class="keyword">unsigned</span> <span class="keyword">int</span> ThreeQuarters = (<span class="keyword">unsigned</span> <span class="keyword">int</span>)((BitsInUnignedInt * <span class="number">3</span>) / <span class="number">4</span>);
<span class="keyword">unsigned</span> <span class="keyword">int</span> OneEighth = (<span class="keyword">unsigned</span> <span class="keyword">int</span>)(BitsInUnignedInt / <span class="number">8</span>);
<span class="keyword">unsigned</span> <span class="keyword">int</span> HighBits = (<span class="keyword">unsigned</span> <span class="keyword">int</span>)(<span class="number">0xFFFFFFFF</span>) << (BitsInUnignedInt - OneEighth);
<span class="keyword">unsigned</span> <span class="keyword">int</span> hash = <span class="number">0</span>;
<span class="keyword">unsigned</span> <span class="keyword">int</span> test = <span class="number">0</span>;
<span class="keyword">while</span> (*str)
{
hash = (hash << OneEighth) + (*str++);
<span class="keyword">if</span> ((test = hash & HighBits) != <span class="number">0</span>)
{
hash = ((hash ^ (test >> ThreeQuarters)) & (~HighBits));
}
}
<span class="keyword">return</span> (hash & <span class="number">0x7FFFFFFF</span>);
}
<span class="comment">// ELF Hash Function</span>
<span class="keyword">unsigned</span> <span class="keyword">int</span> ELFHash(<span class="keyword">char</span> *str)
{
<span class="keyword">unsigned</span> <span class="keyword">int</span> hash = <span class="number">0</span>;
<span class="keyword">unsigned</span> <span class="keyword">int</span> x = <span class="number">0</span>;
<span class="keyword">while</span> (*str)
{
hash = (hash << <span class="number">4</span>) + (*str++);
<span class="keyword">if</span> ((x = hash & <span class="number">0xF0000000</span>L) != <span class="number">0</span>)
{
hash ^= (x >> <span class="number">24</span>);
hash &= ~x;
}
}
<span class="keyword">return</span> (hash & <span class="number">0x7FFFFFFF</span>);
}
<span class="comment">// BKDR Hash Function</span>
<span class="keyword">unsigned</span> <span class="keyword">int</span> BKDRHash(<span class="keyword">char</span> *str)
{
<span class="keyword">unsigned</span> <span class="keyword">int</span> seed = <span class="number">131</span>; <span class="comment">// 31 131 1313 13131 131313 etc..</span>
<span class="keyword">unsigned</span> <span class="keyword">int</span> hash = <span class="number">0</span>;
<span class="keyword">while</span> (*str)
{
hash = hash * seed + (*str++);
}
<span class="keyword">return</span> (hash & <span class="number">0x7FFFFFFF</span>);
}
<span class="comment">// DJB Hash Function</span>
<span class="keyword">unsigned</span> <span class="keyword">int</span> DJBHash(<span class="keyword">char</span> *str)
{
<span class="keyword">unsigned</span> <span class="keyword">int</span> hash = <span class="number">5381</span>;
<span class="keyword">while</span> (*str)
{
hash += (hash << <span class="number">5</span>) + (*str++);
}
<span class="keyword">return</span> (hash & <span class="number">0x7FFFFFFF</span>);
}
<span class="comment">// AP Hash Function</span>
<span class="keyword">unsigned</span> <span class="keyword">int</span> APHash(<span class="keyword">char</span> *str)
{
<span class="keyword">unsigned</span> <span class="keyword">int</span> hash = <span class="number">0</span>;
<span class="keyword">int</span> i;
<span class="keyword">for</span> (i=<span class="number">0</span>; *str; i++)
{
<span class="keyword">if</span> ((i & <span class="number">1</span>) == <span class="number">0</span>)
{
hash ^= ((hash << <span class="number">7</span>) ^ (*str++) ^ (hash >> <span class="number">3</span>));
}
<span class="keyword">else</span>
{
hash ^= (~((hash << <span class="number">11</span>) ^ (*str++) ^ (hash >> <span class="number">5</span>)));
}
}
<span class="keyword">return</span> (hash & <span class="number">0x7FFFFFFF</span>);
}
</pre></td></tr></table></figure>
]]></content>
<summary type="html">
<![CDATA[<p>常见的字符串Hash算法如下,ucc中对符号表使用的是ELFHash,查了一下貌似不是效果非常好的hash算法。也列一列常用的hash算法以备不时之需。
]]>
</summary>
<category term="algorithm" scheme="http://zhangxian.me/tags/algorithm/"/>
</entry>
<entry>
<title><![CDATA[关于动态规划(DP)的一点心得]]></title>
<link href="http://zhangxian.me/2014/05/04/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92_DP%E6%80%BB%E7%BB%93/"/>
<id>http://zhangxian.me/2014/05/04/动态规划_DP总结/</id>
<published>2014-05-03T16:16:35.000Z</published>
<updated>2014-10-18T06:50:37.000Z</updated>
<content type="html"><![CDATA[<h3 id="-">概述:了解动态规划</h3>
<hr>
<p>动态规划算法一般都是基于一个递推公式和一组初始状态,当前子问题解将由上一次子问题的解推出,也就是传说中的(全局最优解包含局部最优解)一般用DP求解一个问题只需要多项式时间复杂度,因此要比回溯法和暴力求解法要快很多。</p>
<p>所以:我们需要求解一个状态的最优解,然后在它的帮助下找到下一个状态的最优解(注意这里是帮助,推出下一个状态的最优解,不一定依靠一个子问题的最优解,可能是一组状态的最优解进行筛选)
<a id="more"></a></p>
<h3 id="-">关键:如何找到”状态“和”递推公式“</h3>
<hr>
<p>所谓状态,即用来描述该问题子状态的解。状态转移方程->一些子问题的最优解推导出另一个规模更大的子问题的求解(状态转移方程这个词造的真好)</p>
<p>构造状态就成为了关键,怎么构造状态呢?</p>
<p>看一个典型的DP问题——0-1背包问题:</p>
<p>话说有一哥们去森林里玩发现了一堆宝石,他数了数,一共有n个。 但他身上能装宝石的就只有一个背包,背包的容量为C。这哥们把n个宝石排成一排并编上号: 0,1,2,…,n-1。第i个宝石对应的体积和价值分别为V[i]和W[i] 。排好后这哥们开始思考: 背包总共也就只能装下体积为C的东西,那我要装下哪些宝石才能让我获得最大的利益呢?</p>
<p>构造状态转移方程的关键在于,整个计算的规模是不断的减小的,现在我们的问题是找出把问题联系在一起的状态,要穷举出所有的状态。问题是要保证最后得到的价值是最大的,状态的值是->当前状态下的最大价值。</p>
<p>降低问题规模的方法来分析问题,我们在组合数学里已经非常熟悉了,先随便给宝石安排一个顺序,编号是1—n,求解的应该是i个宝石放在容量为n的袋子里面,按照最后一个编号为n的宝石的状态进行分类<code>(最后面那个n号宝石放在背包里|n号宝石不在背包里)</code>两种,不管怎么样,宝石的规模都会少1。OK,按照这个想法继续。因为我们每次都是按照最后一个宝石进行分类的,所以假设d(i, j)是前i个宝石放在容量剩余j的背包里,能获得的最大价值,假设i-1个宝石放在容量为n的背包里的最优解 和 i-1个宝石放在容量为j-[第n个宝石的体积]都已知。规模在减小,当然这种假设是成立的,初始条件是,0个宝石放在袋子里价值都是0。在i的规模不断减少的同时,j的规模也开始按照策略减少了,而所有的状态是可以枚举出来的。</p>
<p>状态转移方程是:<code>d(i, j)=max{ d(i-1, j), d(i-1,j-V[i-1]) + W[i-1] }</code>。
到此,状态表格和表格的填表规则已经规定完毕,剩下的就是按照规模从小到大的顺序开始填表了,要求的d(i, C),只要确定d(i-1, 0)到d(i-1, C)的这组最优解即可......d(0, 0)到d(0, C)这一组是已知的。</p>
<h4 id="-">背包问题的代码如下:</h4>
<hr>
<figure class="highlight c"><table><tr><td class="gutter"><pre>1
2
3
4
5
6
7
8
9