如何看待中國編程/演算法教育總是教一些沒用的、無意義的古老的東西,不涉及語言新標準?

本人OI蒟蒻,非常反對中國青少年編程教育形式。比如說

1.在演算法競賽當中,提倡printf和scanf而不是cout/cin;

2.幾乎沒有人逃得過初學時的i++和++i區別;

3.不使用C++11/14新標準;


黑OI可以,但是黑得這麼低級就不對了。

首先,我搞OI那麼多年,從來沒學過i++ + ++i,樓主估計上了假的OI課吧?

OI的特點(同時也是黑點)是:「正確和效率高於一切」。

「正確」高於一切還好說,寫程序當然要正確無bug,即使你只能寫騙分或暴力演算法,但是這個演算法本身不能有錯。

問題在於「效率高於一切」。

這個效率包含兩點:編程的效率和程序的運行效率。

對於程序的運行效率而言,題主所說的「scanf/printf」,其實隸屬於更大的話題:C子集。

熟悉C++的都知道,C子集是「高效率」的代名詞。因此,在OI中,即使是C++選手,C子集也被大量的使用。scanf/printf只是其中一例,除此之外還包括諸如用大的靜態數組代替vector(除非這樣做會MLE,例如稀疏圖的鄰接表)等。OI大面積使用C子集,就是為了讓程序更快。

你可能會這樣反駁我:既然C子集那麼高效,那幹嘛不直接用C語言,幹嘛要用C++?

這就要提到前面的「編程效率」。C++ STL提供了很多數據結構的實現,這將大大的減少我們編程的時間,而且也減少了出bug的可能。

但是,C++中「++」的貢獻也就停止在「庫」上了,只要是STL無關的代碼幾乎都是用C子集。而且很多時候為了兼顧運行效率,有像棧和隊列的簡單的數據結構還是會自己寫。scanf/printf也是類似。scanf/printf並不會非常複雜,但它帶來的運行效率提升巨大。

至於C++11/14,我能想到和效率有關的,只有右值引用、constexpr(運行效率)與auto、for(a : b)循環(編程效率),而這些除了constexpr(編譯時運算的黑科技),改進也不會非常明顯(其它特性基本只和「++」部分有關的,然而我用C子集)。

其實,OI的缺點在於過分的追求效率,而不是什麼「教一些沒用、無意義的古老的東西」。能讓自己的程序擁有最高效率,這本身就是有用、有意義的東西。只不過,在實際開發中,效率並不是唯一因素。我們還要照顧代碼的可維護性、可擴展性等問題。這時,OI那種片面追求效率的寫法就不太合適。

====================================================

補充一點,C++的貢獻除了STL外還包括「語法糖」(給語法糖加雙引號因為這些實際上不是語法糖,但是在OI中被當作語法糖使用)。例如引用、重載運算符,以及利用struct的成員函數把xx(a, b, c)寫成a.xx(b, c)的形式等,但真正的OO特性(封裝、繼承、多態)是幾乎用不上的。


不好意思沒學過i+++++i,我恰好逃過了?


事先聲明,我不是OI/ACM黨,我只是見過一群OI黨,外加刷過一些OJ而已

1、iostream本身就是C++標準庫設計失誤的典型例子,除了抽象層次更高,更便於初學者理解和使用(而不需要像scanf那樣一開始就解釋一大堆有的沒的亂七八糟的無關問題)之外並沒有什麼特別的好處。而默認情況下不關同步iostream的速度比cstdio慢一大截,在競賽中這是極其致命的。

2、題主很可能在胡說八道——應試體制下的任何老師,也許會為了應試而教一些「歪門邪道」,但絕對不可能教一些會把考試搞砸的「歪門邪道」。OI不是計算機二級,它是要考機試的——而這種譚浩強式的寫法,現代編譯器給不給過都不一定,更別提正確性了。所以題主很可能在胡說八道——幾乎不可能有老師會教這種把比賽搞砸的寫法。

3、NOI系列活動標準競賽環境(2016年11月08日更新)

GCC 4.8.4 在默認參數下是不支持C++11的,所以無解。而且C++11隻有右值引用等少數特性跟運行效率有關,像shared_ptr之類的特性在競賽中是根本用不到的。


因為演算法競賽不是抽象競賽……

OI 的主題是正確的演算法 + 快的實現,而不是研究為什麼特定情況下 scanf/printf 快而 cin/cout 慢,直接放棄使用 cin/cout 是一個很切合 OI 目的的做法。

此外因為 OI 不可依賴編譯器優化來做,抽象的代價可能是慘重的(你可以參考 vczh 說的「不開 O2 的話你就能看到抽象的力量」),作為避險,我從來不用 vector;因為 OI 題目的數據範圍都是事先給好的,我也幾乎不會 new——對於需要鏈表的(例如圖論,鄰接表幾乎是 dominant 選擇),定義一個巨大的靜態數組,然後從裡面拿指針即可,這樣你可以保持指針這一層抽象(而不是裸用數組下標),又可以避免分配動態內存的開銷。

為什麼我用 std::sort 和 std::map?因為我不會寫快排和紅黑樹。(其實最後我會寫了,但是寫得很醜。)另外 std::sort 的每次比較都會是函數調用——因為它實際上在用 std::less 的函數調用運算符。因為我接受自己用 std::sort,所以就接受了小於號重載。插敘:早期使用大整數運算的時候還會重載運算(當然要特別注意傳常引用而不是副本!),不過後來用不著大整數運算了。

提示:以上做法並不能讓你在 OI 中成功,但是可以盡量避免因為非演算法原因失誤。


不不不,我中學上oi課時可沒學過i+++++i,你可能是上了假的oi課,不要扣一個中國oi的帽子

printf比cout快至少3倍


0. scanf和printf的類型可是依賴類型!(好吧我知道C/C++沒有真的DT,這條當我說笑了)

1. 誰教你的?打死他就好。無論i+++i是不是ub,都不能把副作用和值混到一起。

2. C++11/14在競賽中最大的好處是type deduction(auto),會方便很多。不過就算沒有,自己標類型也不是很累(很複雜的除外,不過OI你能遇到多複雜的?)。

另一項好處就是STL中的ha希表和shared_ptr,不過TR1湊合著也能用吧,更何況NOI系列比賽用pb_ds都可以的。

所以說如果使用新標準肯定很吼啊,但是沒有還是可以活的。


我跟你講,OI這個比賽主要的形式其實是上機……如果你的老師總教一些沒用的東西,你可以選擇不聽。反正最後是用成績說話。

i++和++i真的是不同的。你非要假裝相同么……

c++11和14沒有確實有點痛,如果我突然變年輕10歲的話我會覺得不讓我用#include &很蛋疼,畢竟我也背不下來mt19937,這個能在庫里直接有還是很好的。(不過我手寫的變種lagged fibonacci從來沒拖過我後腿就是了)

unique_ptr和shared_ptr反倒沒有那麼重要,比賽里你真的想手工管內存的。auto和lambda或許有用,但是感覺很難派上大用場。


利益相關:OIer

首先也不好意思的說一句,我也沒學過i+++++i,你可能學的假的OI

至於cincout與printf和scanf,主要是效率的問題,演算法競賽連wys這種人都有,讀入的時間也是很重要的。

(況且還有讀入優化這種東西的存在)

本來OI就是競賽啊,青少年編程教育可能更加工程向吧。


i+++++i 早就沒有人問了吧......即便是OI圈也早就不屑於這種譚浩強式的語言問題了。

使用 scanf/printf 而不是 iostream 的原因是 std::cin/std::cout 的速度十分可憐...你做個輸入量大的題就明白了。而且格式化輸出有很多地方會方便一些。

至於不支持 C++11/14 新標準是因為 CCF 傻逼。我自己打 Codeforces 從來都是開 C++14 交題的。

話說語言方面並不是 OI 的核心吧......能做題就行管那麼多幹什麼(


沒遇到過i+++++++i之類的東西,用printf而不是cout什麼的。。。教材只是要提供一份可以運行的代碼,沒說你一定要這麼寫。

教演算法的時候主要還是靠偽碼和圖解,畢竟,真實代碼實在是太抽象了,看著蛋疼。至於說演算法教育會用到源代碼,那。。。總要給出一個可以運行的代碼段吧。。。實際上很多時候那些代碼段也就是和偽碼的作用差不多。

至於C++11/14,裡面有很多功能都是需要顛覆原有的思路的,要把這些思路摸透到可以教學的程度,說不定時間還不夠的說。。。但是,總的來說,這和演算法沒什麼關係,畢竟,C++98和11的區別大可看作是文言文和白話文的區別,只是說法不同,本質沒區別


也不知算不算題外話…… C++14 比較完備的 constexpr 可能是真的能改變比賽的東西。

它有可能讓部分題的做法傾向編譯時打表,而這時演算法效率相對就不重要了。


雖然我搞OI時候用的basic和pascal,但就大學中有限的ACM的經驗看,可能我是一個假OIer

i+++ +i這種,我從一開始學C的時候就知道它是不好的代碼,當然知道它是ub是很多年以後的事情了,但至少不會像題主說的「沒有人能逃過」,至少我老師是跟我說清楚了,對了,我們用的就是譚浩強的教材,可能是學校和老師不同吧

至於printf和cout的區別,我懂題主的意思,因為我是工程向,提倡演算法競賽考演算法而不考細節的,如果有人用java寫了個最優演算法卻比C++寫的次優演算法更慢,我認為就競賽本身來講,還是應該讓java的選手得更高分,如果是比賽演算法思想的話,但是這個在現實操作中有諸多困難,OJ要做自動化判題,計算時間,也只能用一刀切的辦法,再說實際工作中很多時候你面對的可能也是這種細節上的效率問題,在不影響可讀性的前提下,多了解一些這種知識也不算什麼錯

而新標準的問題,用得很少,我一般gcc用gnu0x的std,經驗有限不太能看得出來新標準對刷題有什麼太大幫助,可能印象中新標準中大都是一些語法糖吧


1.printf和scanf大部分情況下比cout/cin快; 雖然不見得快到哪裡去,但堅持cout/cin也不會給你加分呀

2.這年代把譚浩強抓出來也不會讓你學i++++i了呀!!!

3.C++11/14新功能對演算法而言用處不大, 在ACM,撇開world final這樣明確說明支持C++14的大比賽, 對於普通的線上賽和校賽你還要花時間研究他是否支持C++11/14 , 一個不小心不行就是浪費時間呀;


1. 因為很少有人能合理利用 std::ios::sync_with_stdio(false)

格式化字元串相當於一種模板語言,C語言可以編譯,但是它不行,必須運行時解析。而 C++ 與之相比,格式化輸出是很多個函數調用,所以不同步的情況下,各有各的性能損失。

2. 一個表達式中帶兩個自增自減運算符的書,就不要看了。自增自減和其它運算符混用的書,可以看但最好別這麼寫。

如果把國產教材(清華大學出版社出的那堆垃圾書)排除在外,幾乎沒有書這麼寫吧。

3. 標準委員會不負責寫教程。從專家看的規範,轉化成新手看的教程需要時間。c++14出來的時候,11的英文書都沒幾本,中文的書更慢。更別說學校那幫老師臨時學習,再把它加到課程大綱里了。


這個問題應該這樣問:

為何中國大學教育大部分學科都是教一些沒用的、無意義的古老的東西?

1 大學的重點並非授課

大學靠什麼排名?靠什麼拿錢?靠paper、靠論文發表數量,但絕非靠教學。只能保證講座前有老師、老師上課時在教室、在教室時會講課。教的好不好?意義不大,畢竟,評價一個大學是否nb看的是學術成果,靠的是paper發表數。

在《北京大學教授晉陞申報條件》上明確寫了「作為第一作者或通訊作者,在本學科主流學術期刊上發表SCI、EI收錄學術論文4篇以上;或作為第一作者或通訊作者,在本學科主流學術期刊上發表SCI、EI收錄學術論文2篇以上且獲得授權三年以上且至今仍處於授權保護狀態的國家發明專利2項以上」。

老師教的再好也沒用,物競天擇,要麼發paper,要麼開公司,教書?呵呵

2 老師並沒有能力教你

國內大學對於教師的招生標準是非博士、博士後不要,而所謂的博士、博士後發論文,寫寫paper可拿手,自有一套忽悠大法,真讓他們去干項目,擼起袖子寫代碼,就為難他們了。

而且,真有能力博士都在BAT里拿百萬年薪,誰樂意在學校里拿個微薄薪資,在官僚體制裡面艱難的掙扎呢?

頂級人工智慧博士年薪以百萬美元計

而高校老師的薪資是多少呢?

這樣的薪資在北上廣活下去都艱難,哪裡招得到優秀的人才呢?沒有人才,那如何才能授好課呢?老師不會、教不了目前企業里的技術,比如Web前端開發、J2EE開發等等,所以,高校並沒有能力培養企業所需要的人才。


鄙人軟體工程本科生在讀。

個人認為題主所言「中國編程/演算法教育總是教一些沒用的、無意義的東西」言重了,古老可能就的確是比較古老了。但是你不能因為新特性很好用,就想把一些老的東西給批判一番。

PS: 鄙人不是競賽大神,以下說法可能更偏向工程應用。。

鄙人的觀點是,如果是計算機相關專業,想要深入研究計算機或者編程語言,僅僅緊跟語言新規範並且會用,是不夠的。如果只是其他專業的普適性教育,目前國內高校教的的確是跟不上時代的發展了。

----------

首先先說一下個人對高校編程教學內容過時的原因一些看法:

1. 語言新特性更新得快,高校老師一般有科研任務,高校老師也有學習成本,可能懶得與時俱進。

2. 教材的選擇方面,市面上教材版本頻出,一些經典的教程,可能更加適合編程入門者的學習,而當一本教材被認為是經典的時候,語言新特性已經不知道高到哪裡去了。為了保證教材的普適性和經典性,學校選擇的教材難免不能與時俱進。

3.本高校oj評測不能支持新特性,學生練習新特性的平台少,老師評測檢查不便。

以上諸多原因導致高校編程課程教學沒能與時俱進。

-------------

嗯,,,printf的確比cout快。。。acm比賽的時候有時間限制那。。。一般人都還是用回printf scanf對吧。。

與時俱進我是提倡的,要求所有國內的高校的編程教育都與時俱進可能不太現實 =_=

這個時候只有自己在課餘時間提升了。買本《C++ Prime》第五版啃(不過這本也沒有C++14可能也不符合題主的要求了(逃))

--------------

98, 03 版本的c++,裡面一些思想並不是可以完全放棄的,雖然不否認頂層的介面調用更省事更加方便。講幾個例子:

例子一:

大一進實驗室,面試的師兄問,將一個string數字和int數字互相轉換,你有什麼思路。

c++字元串遍歷,然後轉int,之類的,雖然本系的oj上做過類似題目,但是其中邊界處理啥的,一些細節說得不夠嚴謹,被師兄轟炸得無地自容。。。好吧最後因為運氣還是進了。

今年我和之前的師兄面試新一屆的大一師弟,師兄問了同一個問題,師弟們的第一反應是這樣的:

然後他們都說,本系的oj升級支持了c++11,這種問題都直接用庫裡面的to_str(),沒有細想過,師弟們只能臨時按照自己的理解來嘗試性回答,基本上掉進了我之前的坑(捂臉)。。結果全部面試完,不同人對於演算法思想的理解水平清晰可見了。

之後我想,可能大的IT公司的面試也是這樣子的吧,如果只是追求語言特性沒有深入了解一些本質的東西,估計可能以後發展遇到的瓶頸會大一點吧

例子二:

平時學習數據結構的時候,如果只著眼於熟練運用STL,但是沒有自己手動底層實現一遍相關的數據結構,感覺無論是從知識理解上還是演算法創新上競爭力都會大大降低。

例子三:

旁聽去了BAT實習的師兄們的經驗,一些公司的舊的大的項目,在初代版本完成時並沒有新的特性,一個巨大的軟體工程的重構需要花費的成本是很值得考慮的。為了項目的穩定性,一般會沿用以前的代碼,這樣的話如果僅僅只會使用新特性是遠遠不夠用的。

------------------

嗯,所以答主認為,必須要認識到中國編程/演算法教育是跟不上時代潮流的,但是也不是編程界的糟粕,題主的提問給我感覺是對那些舊的知識非常嫌棄,這應該是不對的。對於計算機相關專業的同學來說,認識到學校教育跟不上,然後再在此基礎上自己努力去跟上時代潮流,兩面兼顧,才能更好提高自己的核心競爭力。

個人一些理解,如有什麼naive的地方,望各位大佬輕噴=_=


有沒有意思我不知道,我只知道挺有用的。

看到國外一本標準化教材,巴朗AP計算機的,裡面對i++和++i的表述就不清楚。我和教這課的老師爭了半天,她非說書上是對的。

所以我發了個郵件給作者和出版社,

他們說下一版就會改。

至於printf/cout,主要是速度和格式問題。

C++新標準不用,也主要是因為大多國內OIer對STL還是了解少,用得不多,和教育方式真沒啥關係。

不過IOI都是C++14了……


講道理,大佬們哪裡用scanf,不都是getchar嗎!


關於scanf/printf,我就舉個工程實例吧

我希望進行格式話的輸入輸出,輸入部分為命令行分析,輸出部分會把幾十個參數統一打包成一個字元串命令行再加密。

需要允許通過外部引用格式

比如如下簡單例子:

//In Configure File
%d,%d,%d
%d %d %d
%d:%d:%d

//Read Configure
vector& cmds;
int count; // read from file or somewhere else
cmd.reserve(count);
char buffer[256];
while(count--){
memset(buffer,0,256);
fin.getline(buffer,255);
cmds.push_back(buffer);
}

//When Using cmds

int idx = x ; // input

printf(cmds[idx].c_str(),a,b,c);

你準備如何用cout來實現同樣的代碼呢?在不降低可維護性的情況下


再給你補充一個

如何看待C11標準特性在C程序員中很少用

因為cin cout設計上有問題啊

這東西設計裡面帶一群拖油瓶

所以慢

反過來雖然scanf printf古樸

但是他帶的拖油瓶少 就這樣

第二個問題 請問哪本書教你這個 直接撕掉謝謝

劉汝佳的書 和白書都沒有這類問題

第三個問題

語言版本和演算法有毛關係

真正的dalao都是一堆花式宏 不知道比各種語言特性寫的快到哪裡去了


推薦閱讀:

選擇編程語言對初學者有多大幫助?
epoll編程,如何實現高並發伺服器開發?
什麼人適合當程序員?
如何提高自己的android編程能力?
為什麼公司不給實習生看公司代碼?

TAG:演算法 | 編程 | C | OI |