① 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)。