① NicoNico動畫唱見手人氣排行榜TOP100 http://v.youku.com/v_show/id_XMzEwMjg2NTg4.html
嗯。。。。蠻有興趣的,我整理一下吧。需要一段時間。。。
先說明一下集記方式:選取歌手最高再生5曲,除去最高再生曲剩餘四曲再生數+mylist數X15=得分(B站視頻av153579)
100 sm12421592 マトリョシカ歌ってみた-游
宮下游,通稱:游 男性【mylist/7641983】
09年7月up第一首歌。
聲線中性,特點是有氣無力的翻唱=w=
雖然經常有「性別が迷子」的tag,但是男性無誤~
個人喜歡他的 え?あぁ、そう。
覺得他適合唱獵奇類的歌,
比較有名是:結ンデ開イテ羅剎ト骸
還有:後追い自殺に定評のあるみっちゃん
99 sm6457081 【飛鳥支店】 聖徳太子でぽっぴっぽー 【歌ってみた】
苦本,自稱:苦い人 男性【mylist/739792】
沒想到他會在榜上!不是很出名的人,但是nico翻唱的老人啦,07年5月第一次投稿翻唱!
特點:聲線很像《搞笑漫畫日和》裡面的聖徳太子(前田 剛),還有若本 規夫(nico網路記)~
翻唱范圍很廣,御三家都有。還會自己做替歌~
非常喜歡他,因為太子的歌都非常有趣!個人還是日和控。
推薦:妹子が倒せない(short)(エアーマンが倒せない的替歌)
98 sm3729302 【一周年記念】組曲『ニコニコ動畫』をうp主が自ら歌った
しも 男性【翻唱:mylist/7229687 本體(無誤):mylist/1535765】
與其說翻唱出名,不如說組曲出名啊!
nico上最著名的組曲的作者。(niconico動畫,流星群,七色等)
翻唱自己做的組曲時完全是惡意賣萌w
歌曲常有tag: 殘念な天才,ニコニコ史上最大の黒歴史
兄貴控~翻唱都以搞笑為主w
97 sm6058540 【ミクオリジナル】signを歌ってみた【ルシュカ】
ルシュカ 女性【mylist/7975989】
特點:翻唱很有感情,英語能力非常好。
初投稿就是英語版的黑岩★射手
96 sm13500891 ★「コネクト」歌ってみました Ver-irony
irony 女性【mylist/11342801】
初投稿:★「初めての戀が終わる時」 Retake(再MIX)Ver-irony 就受到了高評價。
「コネクト」翻唱水平很高,獲得了爆發的人氣,在12年1月21號獲得了百萬再生。
95 sm11752698 【V系風アレンジ】蜜蜂 -mitsubachi-【マチゲリータ】
マチゲリータ 男性【翻唱:mylist/5274521 自作曲:mylist/4713790】
來自大網路:生日1月24日。身長173cm。體重69kg。AB型。現在20歳。
聲線工口w 也以マチゲリータP身份活動。現在使用的VOCALOID產品:初音ミク、鏡音リン・レン、MEIKO、KAITO、がくっぽいど(神威)、巡音ルカ、初音ミクAppend、メグッポイド(GUMI)、鏡音リンAppend、VY2。
推薦歌曲:【ファミマ入店音】ファミマ入ったら魔界だった【マチゲ×このり×meola】
這首是再生最多的歌。
94 nm9653304 ドSラバーズを歌ってみた。
うらたぬき 通稱:うらた 男性 【聲真似曲mylist/5433669 普通:mylist/11617226】
特點:與銀魂の登場人物である沖田総悟的聲音相似。
歌曲以替歌為主,當然也有普通的歌,但人氣不如替歌。
93 sm2062244 第2次スーパーロボット大戦α OP【SKILL】やまだんstyle
やまだん 男性【mylist/2747614】
07年就開始投稿的早期歌手!燃系!和湯毛組成軟鉄兄弟,與鋼兵關系也很好~
翻唱特點:原曲至上主義,影山風。ニコニコ大會議常客w 0910參加4場,10秋,1011in 高松。公式生放送的出演較多。
92 sm10411165 「GO!GO!MANIAC」を歌ってみた*ななひら
ななひら 女性【user/2524526】
妹系萌音歌手~同人歌手,
同人音楽サークル「ふぉれすとぴれお」にボーカル所屬。(nico大網路)
UTAU「春歌ナナ」的聲音提供者。出演過「ニコニコ大會議2009-2010」
91 sm590189 「キョンでエアーマンが倒せない」を歌ってみた
三段峽 男性【mylist/1755991】
特點:與聲優杉田智和的聲音相似,多是虛的替歌。
動畫吹替投稿比翻唱多,演技力評價更高~
90 sm8990785 【栗プリン】「clock lock works」を歌ってみた。
栗プリン 女性【mylist/6385329】
身在韓國的韓國人。自學日語。生放送以歌為主,其次是雜談。
生放送時唱歌水平也很穩定,有「口からCD音源」之稱。
89 sm13148971 【二息歩行】バイト歩行を歌ってみた=ふぁねる【替え歌】
ふぁねる(faneru) 別稱:♂店員 男性【mylist/22821203】
投稿初期自稱♂店員,後使用ふぁねる,愛稱「ねるたん」
與GERO組成[寢下呂企畫],共3作。10年3月末因個人原因隱退,投稿作品全消除(除合唱)。後10年12月28日回歸。
特點:替詞,聲線甜膩(褒獎的意味),搞笑力很高w
88 sm928 「only my railgun」歌い終わっ太。
終太 男性 【mylist/6423557】
翻唱以動畫和PC游戲OP為主,特點:高音。個人覺得聲音很可愛。
UTAU終音オワタ的音源。
87 sm7777246 【巡音ルカオリジナル】Just Be Friendsを歌ってみたΦ串Φ
Φ串Φ 女性 【mylist/4173849】
御姐音。也兼作詞作曲,比如神威的名曲:呼吸
商業作:2010BL游戲《熱砂的樂園》OP的作詞作曲。
86 sm6169650 【替え歌】 「伸びぬラリアット」 を歌ってみた 【トモナシ】
トモナシ 男性【mylist/8909639】
自稱:底辺歌い手(不紅的意味)有稱號:底王
特點:替歌為主,其實是音痴w
也以平沢P的名義活動。名曲:【初音ミク】口內炎【オリジナル曲】
85 sm1624053 『RAINBOW GIRL』歌ってみた
あにー 男性【mylist/3687105】
以東方project楽曲為主,以TaNaBaTa的名義在東方同人音樂圈活動。
84 sm2080385 「ハジメテノオト」を歌ってみました。by that
that 男性【mylist/7308766】
聲音溫柔,治癒系。
與halyosy合作的ダブルラリアット(炒飯歌)和Smiling都是nico上的名曲!
推薦:
「歌に形はないけれど」を歌ってみました。by that × 歌和サクラ
【that × halyosy】 「ダブルラリアット」を歌ってみた
83 sm8058444 just be friends ~piano ver~ 自由に 歌ってみた 【che:櫻井】
che:櫻井 女性 【mylist/7097718】
著名的兩聲類歌手,多以男性的聲音翻唱。實際上從少女音到御姐音都可以唱出來,男性音也可以到很低,
推薦:七色のニコニコ動畫一人で自由に歌ってみた【che:櫻井】
常與ひと里(女性,同為兩聲類)合作,magnet 歌ってみた 【ひと里&che:櫻井】已達300萬再生。
82 sm7389812 【ヘタリア替え歌】おやぶん☆トマトのうた【歌ってみた】
ウタノOB 男性【mylist/13312161】
別名:うたのおやぶん(大網路記載)「野生の親分」作品多為APH中西(親)班(分)牙的替歌。曾經出過「MAG・ネット」的節目(以nico替歌歌手身份),是個聲優,
博客:ht【】tp://kidou【】gakuto.ju【】gem.jp/?pi【】d=1
81 sm3728941 【ジギル】ニコニコ動畫流星群 ちょっとフリーダムに 歌ってみた
ジギル 男性【mylist/11841158】
特點:loli控。美聲,可惜用在不正常的地方!有分裂人格(聲音):ジギ子,其實是自己的loli音。標志是在翻唱歌曲標題上加上ジギル(笑)
與どM二人組成『どロリ』,他們合唱的歌高達八成不正常。
80 sm6654146 【てん】『右肩の蝶』【歌わせて頂きました】
てん 男性【mylist/3918637】
聲音很元氣。感覺適合燃系的歌,吼叫很美好w
79 nm9586383 マヨネーズラバーズ歌ってみた
A24 男性【mylist/8272111】
聲真似的替歌歌手。聲音類似中井和哉,銀魂土方十四郎的替歌為主。
最著名的替歌是和アホの坂田合作的:
【銀魂】パフェマヨリョシカ【歌ってみた】(味覺崩壞的套娃歌w)
再生已達140萬。
78 sm2421488 今更「ジャスコ(男女)」歌ってみた
(′???`) 自稱:初値ジャス子 女性 【mylist/4426391】
謎の中毒性!聲音非常順耳,溫柔姐姐的感覺!
第一次知道這位歌手,現已中毒w
不過,已經好久沒有up歌了,mylist停在08年。
77 sm8582212 『パラジクロロベンゼン』を歌ってみました。/びびあん
びびあん 女性【mylist/7493776】
特點:高音有所成長,低音也具備相當實力,這讓人上癮的歌聲有著很多忠實的粉絲(大網路)
推薦:『十面相』を歌ってみました。/びびあん
比想像中寫的累啊,大概就是這樣,我會慢慢寫下去的。。。每天寫5-10人。
② 怎麼登陸NICO
http://www.nicovideo.jp/
注冊方法如下:不懂日文的可以簡單看下
第1步點擊「アカウント新規登錄ヘ」
選則右邊灰色的「一般會員でアカウント登錄」這個不用掏錢
填寫以下資料
PCメールアドレス:(E-Mail)請填寫真實的郵箱,因為要在郵箱確認提交資料
ニックネーム:(NICO內使用的名字,昵稱)
性別:(性別)
生年月日:(出生日期)
お住まいの地域:(住址)國內的選TAIWAN或HKG就好了
パスワード:(密碼)填寫密碼和確認密碼
秘密の質問・答え:(密碼問題)問題是 1:喜歡的食物是? 2:討厭的食物是? 3:畢業的學校名稱是? 4:母親的姓氏是? 5:喜歡的電影名字是? 6:飼養的寵物名字是? 7:喜歡的藝人是?
答案自己隨便填一個就好,中文英文都行
填好資料點底下的「登錄確認畫面ヘ」
然後進入你填寫的E-Mail里找到「[ニコニコ動畫]登錄完了手続きのお願い」這個郵件,將「下記のURLにアクセスすると登錄完了となります。」底下的網址打開就行了
登錄頁面:
メールアドレス(郵件地址):輸入你注冊的郵箱
パスワード(密碼):輸入你注冊的密碼
點擊ログイン登錄
登錄後會在頁面上角顯示「ニコニコ - 動畫(動態視頻)|靜畫(靜態視頻)|生放送(直播)| チャンネル(分類頻道) … その他(其他)▼」「一般會員某某(你的昵稱)さん△ プレミア(付費)會員登錄。。。マイページ(我的主頁)| 動畫を投稿(視頻發布)| ランキング(排行榜)| 右上(主要是揭示板) 」
這時,你就可以觀賞站內視頻以及生放送了
③ NicoNico動畫唱見手人氣排行榜TOP100
94的那位完全不認得
原曲是裏表ラバーズ 歌詞= = 是改過的
ドSラバーズを
【MMD銀魂】沖田と土方で 裏表ラバーズ·監禁篇【ドS王子テスト】
(唱見名神馬的…………|||)
其他幾個是哪幾個= =
我比較熟悉的是77.びびあん 72.amu 68.少年T(不太熟) 67.転少女 65.新社會人 57.けったろ
55.鋼兵 51.=のど飴 48.そらる 47.ぽこた(俺の本命) 43.【蓮】 42.花たん 40.燈油 () 34.秋赤音 32.染香 31.腹話 28.96貓 26.clear(會長大人= =) 24.赤飯 20.ピコ 19.蛇足 14.バルシェ 13.実谷なな 12.VIP店長 11.ぐるたみん 7.GERO 6.よっぺい(其人不熟,但是中毒版的爐心熔解挺有名的) 3.halyosy 2.ゴム(國內人氣不知道為什麼不是很高= =) 1.ヒャダイン(人也不算很熟,但是《ストIIの効果音で》超贊
看我如此辛苦……
LZ你懂的
下面歌詞 恕俺無能= =+
④ 電子煙品牌排行榜
電子煙品牌排行榜前八強。
現在網路購買電子煙相當的方便了。建議您直接在網路購買,物美價廉。
據統計,目前在中國網路能查到大概有130家電子煙生產廠家,大部分都有自己的品牌。在規模上,好益康電子煙的競爭力是最大的,好益康是目前全球領先的電子煙品牌,以軍工品質而聞名於世界。
電子煙排行榜前8強排名:
1、好益康電子煙
2、UYD電子煙
3、Eleaf電子煙
4、Nicolites電子煙
5、卡瑞爾電子煙
6、中華電子煙
7、雲端電子煙
8、煙趣世家電子煙
⑤ 輕奢品牌包包有哪些值得推薦
輕奢品牌包包值得推薦的有:Michael Kors、Nico Giani、Simon Miller、Tory Burch、Kate Spade New York。
1、Michael Kors
Michael Kors是一個時裝設計師本人創建的同名奢侈品品牌,中文名字邁克高仕,總部在美國紐約,是當下最受歡迎的輕奢包包品牌,旗下產品包括手袋,服裝,眼鏡等,其品牌的設計風格獨特,簡潔大方,質感也很不錯。
5、Kate Spade New York
由Katherine Noel
Brosnahan創辦,以簡潔靈動的造型,鮮亮大膽的顏色以及活潑有趣的生活態度風靡紐約。它用活力無限的大膽色調表現出Kate Spade New York女孩內心對於未來的美好憧憬和無所畏懼。
⑥ NICO問題
ニコニコ動畫右上角有個総合ランキング 就是排行榜 然後右邊選擇ニコニコ動畫ランキング
然後就能選擇不同分區不同視頻的排行榜了
右上角的期間可以選擇時間段 對象可以也選擇 點擊量就選再生(播放數) 彈幕數就選コメント
直接這個就行?http://www.nicovideo.jp/ranking
⑦ 哪網站有日本動漫排行榜
中文的應該是沒有官方的拉,日文的也看不懂,如果是排行的話可以去訊雷的動漫頻道看看,那裡有TOP的排行和下載量
⑧ 怎麼在NICO上找到好東西
=
=
最簡單的方法就是收看每周的「ニコニコ周刊」,這是nico官方的每周人氣作品排行榜視頻,排名靠前的都是值得一看的作品~
當然還可以直接去nico上扒,先搜索自己感興趣的關鍵詞,再找點擊率高的視頻,偶爾也是可以碰到好東西的~
最後祝好運!
以上~
⑨ niconico動畫排行榜 top100
2011新番動漫排行榜: NO.1 2011.4月開播世界第一初戀 小野寺律在高中時一直暗戀著嵯峨前輩,在一次偶然的機會下,明明打算一直都小心地只在遠處看著他的,明明決定要一直這樣把心情隱藏起來的,但他已出現在我的眼前,那些感情就從體內一點點地湧出,雖然拚命想要忍住,卻還是溢了出來。結果小野寺律向嵯峨前輩告白,由於政宗的一個遮羞的小動作,使雙方都誤會對方,自此分別。 十年過去了,小野寺律完全成長為一個糟糕的大人,就是因為那小小的誤會導致他的性格完全扭曲。小野寺律被分配到丸川書店少女漫畫部當編輯,而這份工作卻不是他想要的。再加上第一天上班就被上司高野先生訓斥+被拿去給漫畫家當模特而被性騷擾!相處之後,高野先生認出是高中時向自己告白的對象小野寺律,而小野寺律卻毫不知情。高三的時候,因為父母離婚,改了姓的嵯峨政宗,其實就是現在的上司高野政宗。他們倆互相說白之後,才知道是個誤會。小野寺律從那件事後,就再也不相信初戀這回事了,他認為初戀是不會實現的。高野政宗卻自信滿滿地說出:「我會再次讓你說喜歡我,覺悟吧!」 NO.2 青之驅魔師 主人公奧村燐,是在正十字學園上學的學生,表面上是人類的後代但實際是魔神撒旦的兒子,只能用降魔劍抑制力量,藤本神父被撒旦殺死後,按照藤本神父遺願找到梅菲斯特·菲雷斯(約翰·浮士德五世)敲開正十字騎士團大門,立志成為除魔師,目標是打敗並狠扁撒旦一頓…… NO.3 好想告訴你第二季 傳說中的「貞子」濃黑的長發,就算是在盛夏也慘白的皮膚,陰沉的臉,連笑容都讓人感到恐懼,只要與她對視3秒就會石化。更不用說接近她,令人發毛的陰森感。就是她——黑沼爽子,一個早已經被遺忘的名字,被大家稱做「貞子」的女生,從小學到高中都是如此。幾乎沒有人知道她的本名,天天都被人害怕著。其實,她只是陰沉了一點點而已,只是而已啦。笑起來有點恐怖,周圍的空氣流動比較詭異點而已。很想很想的和大家融洽的相處,很想很想的盡自己的力量去幫助大家,她有一顆很溫柔、善良、純潔的心,但是卻包裹在「貞子」的外貌下……就這樣,被大家誤解了,害怕了。直到他的出現,陽光般耀眼的他,親切度、爽朗度100%,會對著被稱做「貞子」的她微笑,和她說話,發現她那顆纖細而溫柔的心,並且第一個叫出了她的名字…… 「爽朗王子」和被稱為「女鬼貞子」的校園愛情故事登場. NO.4 惡魔奶爸 男鹿辰巳,石矢魔高中的不良學生,打架無敗記錄,因此被周圍人稱為惡魔。某次在河邊打架的時候遇見了從上游漂來的大叔,男鹿把大叔帶上岸之後大叔卻突然分成兩半,驚魂未定之餘又發現了大叔體內有個嬰兒,誰知道這個小嬰兒竟然是來自魔界未來的魔王——魔王的兒子!男鹿也莫名其妙的成為魔王的父親,從此開始了本來就不平凡的生活。 NO.5 只有神知道的世界2 就讀於舞島學園高中部的桂木桂馬是個喜歡戀愛養成游戲(Galgame)的高中生。曾經成功攻略過10000名女生(游戲中),有著能夠攻略任何類型女性(僅限二次元)的能力,是擁有一切galgame攻略的網站「落とし神」的管理者,以高超的技術被廣大機友尊稱為「落とし神」(攻略之神、攻陷之神)。 某日,一名少女從天而降來到他的面前。這名少女名叫艾露西,從地獄遠道而來的她委託桂馬為她捕獲「驅魂」(駆け魂)的協力者。方法是使被附身的人類戀愛,填補她的心靈縫隙,從而把因在心裡無處容身而逃出來的驅魂捕獲。對現實生活中的女孩退避三舍的桂馬自然毫不猶豫的拒絕了艾露西的要求,但是由於和艾露西結成的契約危及生命,所以他不得不心不甘情不願的承諾幫忙。於是,GAL界的「攻略之神」桂木桂馬終於以三次元世界的女生發動了攻略。 NO.6 死囚樂園 作品中充滿了黑暗的陰謀、血腥的殺戮及致命的戰斗場面,絕對是一部充滿刺激元素的作品。當中的故事講述在神秘的東京大地震10年之後,倖存的男主五十嵐丸太的班上突然出現了一位神秘的「紅色男子」,並把全班無情地殺害了。雖然全班只有丸太一人沒有被殺,但他卻被冠上莫須有的罪名並處以「死刑」,被強制送進了日本唯一的完全民營化監獄「亡靈幻境」。之後,更要為了生存而與其他死囚展開殊死戰。該作於2011年4月推出動畫版。 NO.7 那朵花 以前感情很好的青梅竹馬們,卻在升上高中之後彼此有了距離,不太與人們接觸的主角仁太,很有一般女高中生感覺的鳴子,進入升學高中的集與知利子,沒有繼續升學而展開旅行的「鐵道」,還有從以前到現在都沒有改變的芽衣子。某天,芽衣子忽然間說有「想要實現的願望」而拜託仁太,以此為契機,分散在各處的大家又再次地聚集在一起。 NO.8 美食的俘虜 高級料理餐廳的主廚小松,為了尋找高級,新鮮的料理而認識了美食獵人阿虜,在阿虜的帶領下,小松進入了一個他前所未見的美食的世界,世界各地的珍奇食材,眼花繚亂的高級菜單,千奇百怪的美食家以及前所未見的料理方法都呈現在小松的眼前,他們的冒險開始了。 本作是一部以「美食」為主的漫畫作品,全身的肉在舌間融化並且浮出一層油的的野獸,一整年都結有美味蝦蟹肉的樹、流出源源不絕的香醇白蘭地湧泉的泉水,這是一個探求未知的美味時代,每個美食家的人生菜單分為前菜、湯、魚、肉、主菜、沙拉、甜點、飲料全8種,美食四天王之一的特瑞科為了完成自己人生中的菜單,踏上了尋找珍奇美食的旅程。 NO.9 笨蛋測驗召喚獸 第二季 2011年1月23日,官網公布第二季於11年夏放送。 故事以文月學園為舞台,由各富個性、全力拚搏的角色和可愛的召喚獸們,為那些對文字苦手的粉絲們獻上一幕更直觀的歡樂學園愛情劇。本劇的一大看點在於想像力豐富的笨蛋們的思考方式,被排在最落後班級的學員們究竟能努力到什麼程度呢?! 最新消息則宣稱,第9卷小說預計於2011年1月29日上市。除此之外,漫畫版由擔任《極上生徒會》漫畫執筆的まったくモー助和《keroro軍曹特別訓練☆戰國群星大戰斗!》的作者夢唄漫畫化進行漫畫化,已經在《少年ACE》的6月號開始連載,還曾經三度被製作成廣播劇。攜此勢不可擋之勢宣布TV動畫化的《笨蛋·測驗·召喚獸》,官網上公開了製作陣容。導演是執導過《魔法老師春季版》的鬼才大沼心,系列構成則由《彩雲國物語》等作品的人設擔當大島美和出任。同年4月1日宣布將製作續篇,由於碰巧是愚人節,商品網站更惡搞進軍好萊塢,所以被誤認為假消息。 NO.10 金錢掌控 「C」的故事舞台設定在20xx年,日本正處於嚴重的巨額財政赤字,日本的經濟可謂已經崩壞了,正處於末期的危機當中。但是,一個叫「Sovereign Wealth Fund」的政府系金融機構卻出現了,憑著成功地運用著政府的資金,使政府能夠奇跡地實現財政的重建。但另一方面,雖然日本經濟能夠走出谷底,但在這回復期間,長期的就職問題、失業、自暴自棄者引發的無差別殺人事件、因結緍率的減少導致少子化而感到絕望的人、逃避現實的人、失蹤者及自殺者都急劇增加中... 簡單來說,當時的氣氛使人感到非常不安及擔憂。而就在某一天,就讀都內的經濟學部的大學生主人公?余賀公麿,在他面前出現了一位奇怪的男子真板木,並詢問公麿「如果抵押你的未來,借給你金錢,你又將如何利用自身的才智去使用這筆錢?」。就這様,公麿的世界便從這天起大大地轉變了。 比起單純地模仿現實的金錢世界,「C」將會增加奇幻的元素,用大家以想不到的空想世界描繪金錢的力量。在來臨的4月新番中,這也是一部擁有相當實力的原創作品呢。
⑩ 冒泡排序法和快速排序比較的演算法
打你屁股,這么簡單的問題都不認真研究一下。
冒泡排序是最慢的排序,時間復雜度是 O(n^2)。
快速排序是最快的排序。關於快速排序,我推薦你看看《代碼之美》第二章:我編寫過的最漂亮的代碼。作者所說的最漂亮,就是指效率最高的。
--------------------------------摘自《代碼之美》---------------
當我撰寫關於分治(divide-and-conquer)演算法的論文時,我發現C.A.R. Hoare的Quicksort演算法(「Quicksort」,Computer Journal 5)無疑是各種Quicksort演算法的鼻祖。這是一種解決基本問題的漂亮演算法,可以用優雅的代碼實現。我很喜歡這個演算法,但我總是無法弄明白演算法中最內層的循環。我曾經花兩天的時間來調試一個使用了這個循環的復雜程序,並且幾年以來,當我需要完成類似的任務時,我會很小心地復制這段代碼。雖然這段代碼能夠解決我所遇到的問題,但我卻並沒有真正地理解它。
我後來從Nico Lomuto那裡學到了一種優雅的劃分(partitioning)模式,並且最終編寫出了我能夠理解,甚至能夠證明的Quicksort演算法。William Strunk Jr.針對英語所提出的「良好的寫作風格即為簡練」這條經驗同樣適用於代碼的編寫,因此我遵循了他的建議,「省略不必要的字詞」(來自《The Elements of Style》一書)。我最終將大約40行左右的代碼縮減為十幾行的代碼。因此,如果要回答「你曾編寫過的最漂亮代碼是什麼?」這個問題,那麼我的答案就是:在我編寫的《Programming Pearls, Second Edition》(Addison-Wesley)一書中給出的Quichsort演算法。在示例2-1中給出了用C語言編寫的Quicksort函數。我們在接下來的章節中將進一步地研究和改善這個函數。
【示例】 2-1 Quicksort函數
void quicksort(int l, int u)
{ int i, m;
if (l >= u) return; 10
swap(l, randint(l, u));
m = l;
for (i = l+1; i <= u; i++)
if (x[i] < x[l])
swap(++m, i);
swap(l, m);
quicksort(l, m-1);
quicksort(m+1, u);
}
如果函數的調用形式是quicksort(0, n-1),那麼這段代碼將對一個全局數組x[n]進行排序。函數的兩個參數分別是將要進行排序的子數組的下標:l是較低的下標,而u是較高的下標。函數調用swap(i,j)將會交換x[i]與x[j]這兩個元素。第一次交換操作將會按照均勻分布的方式在l和u之間隨機地選擇一個劃分元素。
在《Programming Pearls》一書中包含了對Quicksort演算法的詳細推導以及正確性證明。在本章的剩餘內容中,我將假設讀者熟悉在《Programming Pearls》中所給出的Quicksort演算法以及在大多數初級演算法教科書中所給出的Quicksort演算法。
如果你把問題改為「在你編寫那些廣為應用的代碼中,哪一段代碼是最漂亮的?」我的答案還是Quicksort演算法。在我和M. D. McIlroy一起編寫的一篇文章("Engineering a sort function," Software-Practice and Experience, Vol. 23, No. 11)中指出了在原來Unix qsort函數中的一個嚴重的性能問題。隨後,我們開始用C語言編寫一個新排序函數庫,並且考慮了許多不同的演算法,包括合並排序(Merge Sort)和堆排序(Heap Sort)等演算法。在比較了Quicksort的幾種實現方案後,我們著手創建自己的Quicksort演算法。在這篇文章中描述了我們如何設計出一個比這個演算法的其他實現要更為清晰,速度更快以及更為健壯的新函數——部分原因是由於這個函數的代碼更為短小。Gordon Bell的名言被證明是正確的:「在計算機系統中,那些最廉價,速度最快以及最為可靠的組件是不存在的。」現在,這個函數已經被使用了10多年的時間,並且沒有出現任何故障。
考慮到通過縮減代碼量所得到的好處,我最後以第三種方式來問自己在本章之初提出的問題。「你沒有編寫過的最漂亮代碼是什麼?」。我如何使用非常少的代碼來實現大量的功能?答案還是和Quicksort有關,特別是對這個演算法的性能分析。我將在下一節給出詳細介紹。
2.2 事倍功半
Quicksort是一種優雅的演算法,這一點有助於對這個演算法進行細致的分析。大約在1980年左右,我與Tony Hoare曾經討論過Quicksort演算法的歷史。他告訴我,當他最初開發出Quicksort時,他認為這種演算法太簡單了,不值得發表,而且直到能夠分析出這種演算法的預期運行時間之後,他才寫出了經典的「Quicksoft」論文。
我們很容易看出,在最壞的情況下,Quicksort可能需要n2的時間來對數組元素進行排序。而在最優的情況下,它將選擇中值作為劃分元素,因此只需nlgn次的比較就可以完成對數組的排序。那麼,對於n個不同值的隨機數組來說,這個演算法平均將進行多少次比較?
Hoare對於這個問題的分析非常漂亮,但不幸的是,其中所使用的數學知識超出了大多數程序員的理解范圍。當我為本科生講授Quicksort演算法時,許多學生即使在費了很大的努力之後,還是無法理解其中的證明過程,這令我非常沮喪。下面,我們將從Hoare的程序開
11
始討論,並且最後將給出一個與他的證明很接近的分析。
我們的任務是對示例2-1中的Quicksort代碼進行修改,以分析在對元素值均不相同的數組進行排序時平均需要進行多少次比較。我們還將努力通過最短的代碼、最短運行時間以及最小存儲空間來得到最深的理解。
為了確定平均比較的次數,我們首先對程序進行修改以統計次數。因此,在內部循環進行比較之前,我們將增加變數comps的值(參見示例2-2)。
【示例2-2】 修改Quicksort的內部循環以統計比較次數。
for (i = l+1; i <= u; i++) {
comps++;
if (x[i] < x[l])
swap(++m, i);
}
如果用一個值n來運行程序,我們將會看到在程序的運行過程中總共進行了多少次比較。如果重復用n來運行程序,並且用統計的方法來分析結果,我們將得到Quicksort在對n個元素進行排序時平均使用了1.4 nlgn次的比較。
在理解程序的行為上,這是一種不錯的方法。通過十三行的代碼和一些實驗可以反應出許多問題。這里,我們引用作家Blaise Pascal和T. S. Eliot的話,「如果我有更多的時間,那麼我給你寫的信就會更短。」現在,我們有充足的時間,因此就讓我們來對代碼進行修改,並且努力編寫出更短(同時更好)的程序。
我們要做的事情就是提高這個演算法的速度,並且盡量增加統計的精確度以及對程序的理解。由於內部循環總是會執行u-l次比較,因此我們可以通過在循環外部增加一個簡單的操作來統計比較次數,這就可以使程序運行得更快一些。在示例2-3的Quicksort演算法中給出了這個修改。
【示例2-3】 Quicksort的內部循環,將遞增操作移到循環的外部
comps += u-l;
for (i = l+1; i <= u; i++)
if (x[i] < x[l])
swap(++m, i);
這個程序會對一個數組進行排序,同時統計比較的次數。不過,如果我們的目標只是統計比較的次數,那麼就不需要對數組進行實際地排序。在示例2-4中去掉了對元素進行排序的「實際操作」,而只是保留了程序中各種函數調用的「框架」。
【示例2-4】將Quicksort演算法的框架縮減為只進行統計
void quickcount(int l, int u)
{ int m;
if (l >= u) return;
m = randint(l, u);
comps += u-l;
quickcount(l, m-1);
quickcount(m+1, u);
}
12
這個程序能夠實現我們的需求,因為Quichsort在選擇劃分元素時採用的是「隨機」方式,並且我們假設所有的元素都是不相等的。現在,這個新程序的運行時間與n成正比,並且相對於示例2-3需要的存儲空間與n成正比來說,現在所需的存儲空間縮減為遞歸堆棧的大小,即存儲空間的平均大小與lgn成正比。
雖然在實際的程序中,數組的下標(l和u)是非常重要的,但在這個框架版本中並不重要。因此,我們可以用一個表示子數組大小的整數(n)來替代這兩個下標(參見示例2-5)
【示例2-5】 在Quicksort代碼框架中使用一個表示子數組大小的參數
void qc(int n)
{ int m;
if (n <= 1) return;
m = randint(1, n);
comps += n-1;
qc(m-1);
qc(n-m);
}
現在,我們可以很自然地把這個過程整理為一個統計比較次數的函數,這個函數將返回在隨機Quicksort演算法中的比較次數。在示例2-6中給出了這個函數。
【示例2-6】 將Quicksort框架實現為一個函數
int cc(int n)
{ int m;
if (n <= 1) return 0;
m = randint(1, n);
return n-1 + cc(m-1) + cc(n-m);
}
在示例2-4、示例2-5和示例2-6中解決的都是相同的基本問題,並且所需的都是相同的運行時間和存儲空間。在後面的每個示例都對這些函數的形式進行了改進,從而比這些函數更為清晰和簡潔。
在定義發明家的矛盾(inventor's paradox)(How To Solve It, Princeton University Press)時,George Póllya指出「計劃越宏大,成功的可能性就越大。」現在,我們就來研究在分析Quicksort時的矛盾。到目前為止,我們遇到的問題是,「當Quicksort對大小為n的數組進行一次排序時,需要進行多少次比較?」我們現在將對這個問題進行擴展,「對於大小為n的隨機數組來說,Quichsort演算法平均需要進行多少次的比較?」我們通過對示例2-6進行擴展以引出示例2-7。
【示例2-7】 偽碼:Quicksort的平均比較次數
float c(int n)
if (n <= 1) return 0
sum = 0
for (m = 1; m <= n; m++)
sum += n-1 + c(m-1) + c(n-m)
return sum/n
如果在輸入的數組中最多隻有一個元素,那麼Quichsort將不會進行比較,如示例2-6
13
中所示。對於更大的n,這段代碼將考慮每個劃分值m(從第一個元素到最後一個,每個都是等可能的)並且確定在這個元素的位置上進行劃分的運行開銷。然後,這段代碼將統計這些開銷的總和(這樣就遞歸地解決了一個大小為m-1的問題和一個大小為n-m的問題),然後將總和除以n得到平均值並返回這個結果。
如果我們能夠計算這個數值,那麼將使我們實驗的功能更加強大。我們現在無需對一個n值運行多次來估計平均值,而只需一個簡單的實驗便可以得到真實的平均值。不幸的是,實現這個功能是要付出代價的:這個程序的運行時間正比於3n(如果是自行參考(self-referential)的,那麼用本章中給出的技術來分析運行時間將是一個很有趣的練習)。
示例2-7中的代碼需要一定的時間開銷,因為它重復計算了中間結果。當在程序中出現這種情況時,我們通常會使用動態編程來存儲中間結果,從而避免重復計算。因此,我們將定義一個表t[N+1],其中在t[n]中存儲c[n],並且按照升序來計算它的值。我們將用N來表示n的最大值,也就是進行排序的數組的大小。在示例2-8中給出了修改後的代碼。
【示例2-8】 在Quicksort中使用動態編程來計算
t[0] = 0
for (n = 1; n <= N; n++)
sum = 0
for (i = 1; i <= n; i++)
sum += n-1 + t[i-1] + t[n-i]
t[n] = sum/n
這個程序只對示例2-7進行了細微的修改,即用t[n]來替換c(n)。它的運行時間將正比於N2,並且所需的存儲空間正比於N。這個程序的優點之一就是:在程序執行結束時,數組t中將包含數組中從元素0到元素N的真實平均值(而不是樣本均值的估計)。我們可以對這些值進行分析,從而生成在Quichsort演算法中統計比較次數的計算公式。
我們現在來對程序做進一步的簡化。第一步就是把n-1移到循環的外面,如示例2-9所示。
【示例2-9】 在Quicksort中把代碼移到循環外面來計算
t[0] = 0
for (n = 1; n <= N; n++)
sum = 0
for (i = 1; i <= n; i++)
sum += t[i-1] + t[n-i]
t[n] = n-1 + sum/n
現在將利用對稱性來對循環做進一步的調整。例如,當n為4時,內部循環計算總和為:
t[0]+t[3] + t[1]+t[2] + t[2]+t[1] + t[3]+t[0]
在上面這些組對中,第一個元素增加而第二個元素減少。因此,我們可以把總和改寫為:
2 * (t[0] + t[1] + t[2] + t[3])
我們可以利用這種對稱性來得到示例2-10中的Quicksort。
【示例2-10】 在Quichsort中利用了對稱性來計算
t[0] = 0
14
for (n = 1; n <= N; n++)
sum = 0
for (i = 0; i < n; i++)
sum += 2 * t[i]
t[n] = n-1 + sum/n
然而,在這段代碼的運行時間中同樣存在著浪費,因為它重復地計算了相同的總和。此時,我們不是把前面所有的元素加在一起,而是在循環外部初始化總和並且加上下一個元素,如示例2-11所示。
【示例2-11】 在Quicksort中刪除了內部循環來計算
sum = 0; t[0] = 0
for (n = 1; n <= N; n++)
sum += 2*t[n-1]
t[n] = n-1 + sum/n
這個小程序確實很有用。程序的運行時間與N成正比,對於每個從1到N的整數,程序將生成一張Quicksort的估計運行時間表。
我們可以很容易地把示例2-11用表格來實現,其中的值可以立即用於進一步的分析。在2-1給出了最初的結果行。
表2-1 示例2-11中實現的表格輸出
N Sum t[n]
0 0 0
1 0 0
2 0 1
3 2 2.667
4 7.333 4.833
5 17 7.4
6 31.8 10.3
7 52.4 13.486
8 79.371 16.921
這張表中的第一行數字是用代碼中的三個常量來進行初始化的。下一行(輸出的第三行)的數值是通過以下公式來計算的:
A3 = A2+1 B3 = B2 + 2*C2 C3 = A2-1 + B3/A3
把這些(相應的)公式記錄下來就使得這張表格變得完整了。這張表格是「我曾經編寫的最漂亮代碼」的很好的證據,即使用少量的代碼完成大量的工作。
但是,如果我們不需要所有的值,那麼情況將會是什麼樣?如果我們更希望通過這種來方式分析一部分數值(例如,在20到232之間所有2的指數值)呢?雖然在示例2-11中構建了完整的表格t,但它只需要使用表格中的最新值。因此,我們可以用變數t的定長空間來替代table t[]的線性空間,如示例2-12所示。
【示例2-12】 Quicksoft 計算——最終版本
sum = 0; t = 0
15
for (n = 1; n <= N; n++)
sum += 2*t
t = n-1 + sum/n
然後,我們可以插入一行代碼來測試n的適應性,並且在必要時輸出這些結果。
這個程序是我們漫長學習旅途的終點。通過本章所採用的方式,我們可以證明Alan Perlis的經驗是正確的:「簡單性並不是在復雜性之前,而是在復雜性之後」 ("Epigrams on Programming," Sigplan Notices, Vol. 17, Issue 9)。