分類
發燒車訊

雷諾:2020 年前電動車續航力將增 3 至 4 成

英國金融時報 (FT) 15 日報導,雷諾 (Renault) 電動車行銷主管 Vincent Carre 表示,電池科技發展極為迅速,他們已把「里程焦慮」(range anxiety) 拋諸腦後,因為幾年內電動車的里程數將會加倍;到 2020 年前,不只里程數加倍,還會額外再增 30% 至 40% 的續航力。   這表示雷諾估計,未來電動車的里程數可達 200 英里以上。業界普遍認為,要是電動車里程超越 200 英里,將有望打入主流車款。LMC Automotive 預估,歐洲電動車、油電混合車、燃料電池車的銷售,今年將增加 30% 至 36 萬輛。    不只雷諾信心滿滿,部分專家也有類似看法。ecomento 15日引述 OilPrice.com 文章報導,電動車可能會出現飛躍成長,以往冰箱、個人電腦剛問世時,也都被視為奢侈品,但不久後就成為家庭必需品,該文認為電動車廣為接受的時刻將近,因為價格將更加經濟實惠。估計等到電池價格降到每千瓦小時 100 或 150 美元,電動車的總持有成本將可減少 75%,和一般汽車相比,極具競爭力。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

南投搬家費用,距離,噸數怎麼算?達人教你簡易估價知識!

分類
發燒車訊

反應不如預期 特斯拉放棄快速換電服務

對於電動車而言,其中一個未能解決的致命傷,就是充電時間往往很長,對比起幾分鐘就能入滿油的傳統汽車來說,的確是個問題。Tesla 原先計劃採用直接換電方式,為車主換電,不用等待電池慢慢充滿。   不過,據 Tesla CEO Elon Musk 最近表示,快速換電服務在測試階段,在 200 個邀請當中,只有 4 至 5 個車主回應,而他們試過一次之後,都沒有再使用這個服務。因此,有鑑於反應冷淡,他們認爲這並不是未來應該繼續發展的計劃。   相對的,Tesla 現時繼續推出 Supercharger 快速充電站,為想要去長途旅程的 Tesla 車主提供免費的快速充電服務。雖然現時的 Model S 支援快速換電,但之後推出的 Model X 可能就會放棄這個功能。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置台北網頁設計,各種案例分享

分類
發燒車訊

特斯拉 5 年內推市占 100 萬台;大眾車款 Model 3 將搶市

電動車大廠特斯拉 (Tesla) 最近 1 份報告指出,預計在 5 年內將特斯拉電動車市占量推上 100 萬台。   《華爾街日報》報導,特斯拉首席技術長 JB Straubel 15 日 在一場會議中提出這項市占率預測;此外,為迎合大眾市場,特斯拉即將推出價值 3.5 萬美元的 Model 3 型電動車,則預計成為銷售量成長最佳的動力來源。 Straubel 另表示,特斯拉 Model 3 型電動車預計在 2017 年問世。   Global Equities Research 的共同創辦人兼分析師 Trip Chowdhry 表示,只要特斯拉的超級電池工廠 Gigafactory 能如期完成,野心勃勃的百萬車輛計畫成功機率就相當高。  

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

南投搬家前需注意的眉眉角角,別等搬了再說!

分類
發燒車訊

2015節能與新能源汽車產業發展成果彙報及展示會-中國國際汽車新能源及技術應用展覽會

時間:2015年10月21-24日   地點:北京•國家會議中心

【主辦單位】

中華人民共和國工業和信息化部
中華人民共和國財政部
中華人民共和國科學技術部
中華人民共和國發展和改革委員會

【協辦單位】

中國汽車工業協會
中國汽車技術研究中心
中國汽車工程學會
中國汽車工程研究院股份有限公司
中國電工技術學會
中國國際貿易促進委員會機械行業分會
中國國際貿易促進委員會汽車行業分會
汽車知識雜誌社
寰球時代汽車投資管理(北京)有限公司

【承辦單位】北京中汽四方會展有限公司

【展覽合作單位】北京盛大超越國際展覽有限公司

展出面積:35,000平方米(預計)
觀眾數量:60,000人次(預計)
展覽週期:每年一屆,2013年首屆

“成果彙報及展示會”主要由會議和展會兩大部分構成。會議方面主要包括節能與新能源汽車發展成果彙報會、節能與新能源汽車技術研討會、電動汽車國際標準研討會、新能源汽車專利成果研討會和示範城市經驗交流會等內容。展會包括節能與新能源汽車發展情況回顧、節能與新能源汽車產業發展規劃成果展、中國國際汽車新能源及技術應用展覽會、節能與新能源汽車發展前景展望。在前兩屆成果展成功舉辦基礎上,2015年展會將分設整車展區、關鍵零部件展區、充電設施展區和試點城市展區,在重點展示25個創新工程項目研究成果基礎上,全面展示節能與新能源汽車產業發展的最新成果。展會同期還將舉辦試乘試駕等體驗活動。

【參展範圍】
節能汽車、純電動車,混合動力車,燃料電池車,輕型電動車,天然氣(液化氣)車,醇類燃料車及其他代用燃料車;
先進內燃機、高效變速器、整車優化設計等節能技術和產品;
電池,燃料電池,電池管理系統,電池的回收和包裝;
電力電容器,飛輪,能源管理系統;
電機,電機保護與控制技術;
充電器及充電站設備及相關配套專案企業、機構;
電動車及其他替代能源汽車的零部件及零部件總成;
加氣設備,儲運設備及技術;
網路管理,可再生能源發電,新型元器件和材料,輕量化;
智慧社區和電網,汽車共用和通訊服務;
檢測,維修,監控,實驗,安全防護裝備;
城市推廣應用示範展示、製造設備、工具及媒體等.

【上屆回顧】

10月21日,為期五天的以“選擇•行動——未來從現在開始”為主題的2014 中國國際汽車新能源及技術應用展暨節能與新能源汽車產業發展規劃成果展覽會(以下簡稱節能與新能源汽車成果展)在北京國家會議中心成功閉幕,展會共吸引來自國內外6萬餘人次的觀展,中央電視臺、北京電視臺、旅遊衛視、中國教育電視臺、新華社、美通社、經濟日報、新浪、搜狐等百餘家中外合作媒體競相報導。

本屆展會得到了中國國家各部委領導的大力指導和支持,10月18日下午,在工業和信息化部相關司局、行業機構領導的陪同下,苗圩部長蒞臨展會表示祝賀並參觀指導,他認真參觀了一汽集團、東風集團、長安集團、北汽集團、豐田汽車、上海通用、吉利汽車、富豪汽車、安凱客車、宇通客車等展臺,詳細瞭解節能與新能源汽車技術研發進程與成果,對企業在節能與新能源汽車發展過程所做的工作、取得的成果和成績給予充分肯定,對行業今後的發展指明方向。他指出,今年的展會在上一屆車展基礎上有較大提升,鼓勵主辦方繼續努力,積極做好明年車展的各項籌備工作,力爭打造品牌展會,為推動我國節能與新能源汽車產業的發展做出積極的貢獻。

中國機械聯合會會長王瑞祥,國家能源委專家諮詢委員會主任、原國家能源局局長張國寶,原機械工業部副部長、重慶市原市委書記張德鄰,原機械工業部副部長、中國電工技術學會理事長孫昌基,原外經貿部部長助理、國家機電產品進口審查辦公室主任徐秉金等領導和專家及總裝備部、國防科工委、商務部、國資委、質檢總局、交通部、環保部等有關單位領導也蒞臨參觀。合肥、哈爾濱、深圳、北京、上海、青島等一批新能源汽車示範推廣應用城市相關負責人,以及三十多家城市政府採購相關領導蒞臨展會並與相關企業進行了合作交流和洽談。

本屆車展還吸引了大批外賓參觀,日本、白俄羅斯、歐洲、美國等地專業觀眾專程前來參觀,千里達和多巴哥駐華大使錢德拉達思•辛格、波蘭駐華大使館、德國駐華大使館等相關人員也蒞臨展會。

對話行業專家  探究新能源汽車產業未來

作為本屆車展最為重要的同期活動,10月17日召開了2014中國節能與新能源汽車產業發展高峰論壇。論壇以“選擇•行動——未來從現在開始”為主題,邀請了中國相關部門的領導、整車與零部件企業集團的高層、配套設施企業集團的高層、管理企業的相關負責人、新能源企業產業園區的領導,以及權威的專家和學者、金融行業的高管等齊聚一堂,就節能與新能源汽車產業發展的戰略目標與方向、汽車企業的節能與新能源戰略與行動、節能與新能源汽車發展規劃及示範城市情況等內容進行了展開式的談論。原國家發改委副主任、國家能源局局長張國寶、國務院發展研究中心產業經濟研究部主任王曉明、中國城市電動汽車創新聯盟副會長陳勁松,整車與零部件企業集團的高層如北京汽車集團、富豪公司、鄭州宇通客車股份有限公司、比亞迪、安凱汽車股份有限公司等嘉賓領導圍繞著本屆論壇的主題進行深入細緻的討論,深入剖析節能與新能源汽車發展規劃示範城市和運營推廣,共同探討以創新的模式協調各方的力量,為新能源汽車的市場推廣形成有效的主推力。

10月18日,同期舉辦了中國國際純電動車、混合動力和燃料電池車及關鍵零部件技術交流研討會。中國汽車技術研究中心電池首席專家王芳博士、中國化學與物理電源行業協會秘書長劉彥龍、中信國安盟固利新能源科技有限公司研究院副院長劉正耀、國網北京市電力公司電力科學研究院電源技術中心主任遲忠君、中國科學院電工研究所研究員、中國電工技術學會電動車輛專委會主任委員溫旭輝、美國(EDI)易迪艾技術長 Andy Frank、北斗經濟技術產業創新聯盟執行副主席張東普和各權威的專家、學者北京交通大學電氣工程學院院長姜久春、哈爾濱工業大學電氣工程院副院長朱春波、清華大學張俊智教授等就動力電池、儲能設備,充電及服務、電機及驅動系統、系統控制與資訊系統及互聯網運用等專題進行深入的技術交流研討。

同期活動

【日期:2015年10月21日】
1、時間:上午9:30-10:00
項目:開館儀式
內容:2015節能與新能源汽車成果展開館儀式
地點:國家會議中心(序廳)

2、時間:全天
項目:2015新能源汽車產業技術創新工程技術交流會
主辦單位:創新工程辦公室、車展組委會;
內容:組織召開創新工程項目技術交流會,作為創新工程項目單位間技術交流、經驗分享的平臺。屆時,工信部、科技部、財政部及發展改革委相關領導將蒞臨指導
地點:國家會議中心

3、時間:上午11:00-11:30
項目:2015車內空氣品質評價工作新聞發佈會,
主辦單位:中國品質認證中心等;
內容:現場發佈2015年車度內空氣品質評價工作結果,向媒體和公眾發佈相應資料和檢測報告,研究、部署下一步車內空氣品質評價工作。
地點:國家會議中心

4、時間:下午
項目:2015車內空氣品質評價工作研討會
主辦單位:中國品質認證中心等;
內容:現場發佈2015年車度內空氣品質評價工作結果,向媒體和公眾發佈相應資料和檢測報告,研究、部署下一步車內空氣品質評價工作。
地點:國家會議中心

5、時間:下午
項目:2015中國互聯網+新能源汽車高峰論壇暨中國國際純電動車、混合動力車和燃料電池車及關鍵零部件技術交流研討會
主辦單位:中國電工技術學會、中國貿促會機械行業分會等;
內容:政產學研用、產業上下游、國內外行業專家齊聚一堂,為中國節能與新能源汽車發展建言獻策;媒體集中採訪
地點:國家會議中心

6、時間:下午
項目:2016年客車藍皮書啟動儀式及新能源商用車研討會
主辦單位:方得網、車展組委會;
內容:研究探討新能源技術在商用車領域的應用情況及未來發展趨勢。
地點:國家會議中心

【日期:2015年10月22日】
1、時間:上午
項目:節能與新能源汽車發展成果彙報會
主辦單位:工業和資訊化部、財政部、科技部、發展改革委;
內容:主會場(全體大會)
地點:國家會議中心一層大宴會廳B+C

2、時間:下午
項目:節能與新能源汽車技術研討會(分會場)
主辦單位:中國汽車工業協會
地點:國家會議中心一層多功能A

3、時間:下午
項目:新能源汽車專利成果研討會(分會場)
主辦單位:中國汽車工程研究院股份有限公司;
地點:國家會議中心三層301A+B

4、時間:下午
項目:新能源汽車示範城市經驗交流會(分會場)
主辦單位:中國汽車工程學會;
地點:國家會議中心三層302A+B

5、時間:下午
項目:電動汽車國際標準研討會
主辦單位:中國汽車技術研究中心;
內容:分會場
地點:國家會議中心三層303A+B

【日期:2015年10月23日】
時間:上午
項目:節能與新能源汽車政府採購資訊洽談會
主辦單位:政府採購資訊報、車展組委會;
內容:國內新能源汽車的推廣主要是通過政府採購等途徑進行,隨著國家節能減排各項政策的落實,新能源汽車的政府採購市場的推廣還有更大空間。
地點:國家會議中心

【日期:2015年10月21-24日】
1、時間:全天
項目:“尊享體驗”試乘試駕活動
內容:設立VIP嘉賓試乘試駕專場;專業觀眾和示範城市代表專場;普通觀眾、市民專場;國外使館官員、海外留學生、外賓及展會觀眾專場;媒體試駕專場;駕校師生、陪練和高校師生專場;團購和車友會專場;高爾夫球友會和金融機構專場等多個場次,讓更多人接觸使用節能與新能源車,通過體驗切身感受節能與新能源汽車的性能和優勢,向社會各界普及推廣節能環保出行理念。
地點:國家會議中心外場、老北京停車場等

2、時間:全天
項目:2015全國高校汽車科技文化節
內容:開幕儀式;高校節能環保知識大賽複賽、決賽、頒獎儀式;高校汽車設計邀請賽頒獎儀式;高校節能環保汽車形象大使聘用儀式;高校師生現場體驗活動等。
地點:國家會議中心

3、時間:全天
項目:車內環保安全知識趣味講堂及抽獎活動
內容:現場開展車內環保安全知識介紹,穿插互動環節答題,每場隨機抽獎。
地點:國家會議中心

4、時間:全天
項目:尋新集贊,尋找新能源汽車有獎
內容:活動現場諮詢台領取表格《尋“新”集贊》,到場館內所有整車展區尋找新能源汽車,到各個展臺印章“贊”,領取精美禮品。
地點:國家會議中心E1-E4館

5、時間:全天
項目:老人•孩子•藍天攝影大賽
內容:由觀眾自行尋找自己喜歡的節能環保和新能源汽車與其合影留念,拍照者可上傳到指定官網曬幸福,參與現場抽獎;現場體驗、風采展示。
地點:國家會議中心E1-E4館

6、時間:全天
項目:Blue Auto 惠享金秋購車節
內容:組織優惠購車活動,通過特價車超市,趣味試駕體驗,看車抽車等環節,讓消費者體驗不一樣的駕乘和購車感受,積累潛在客戶,促進新車成交。
地點:國家會議中心

7、時間:全天
項目:我的地盤 你做主—2015觀眾票選人氣節能與新能源車大獎
內容:由觀眾和線上(微信、微博、官網等)投票,選出最具人氣、最受歡迎、最具影響力的節能車型/純電動車型/混合動力車型/插電式混合動力車型等獎項
地點:國家會議中心

【日期:2015年10月24日】
時間:上午
項目:新心有約—車友沙龍活動
內容:車友聚會;參觀新能源汽車;參與現場活動;專車試乘試駕體驗。
地點:國家會議中心

【展會諮詢】
北京盛大超越國際展覽有限公司
連絡人:岳巍                               
手  機:+86 135 5286 5285                           
電  話: +86 10 6329 0215                   
傳  真: +86 10 5141 8155
E-mail:                  

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

分類
發燒車訊

MySQL 執行計劃詳解

MySQL 原理篇

我們經常使用 MySQL 的執行計劃來查看 SQL 語句的執行效率,接下來分析執行計劃的各個显示內容。

EXPLAIN SELECT * FROM users 
WHERE id IN (SELECT userID FROMuser_address WHERE address = "湖南長沙麓谷") ;

執行計劃的 id

select 查詢的序列號,標識執行的順序

  • id 相同,執行順序由上至下
  • id 不同,如果是子查詢,id 的序號會遞增,id 值越大優先級越高,越先被執行

執行計劃的 select_type

查詢的類型,主要是用於區分普通查詢、聯合查詢、子查詢等。

  • SIMPLE:簡單的 select 查詢,查詢中不包含子查詢或者 union
  • PRIMARY:查詢中包含子部分,最外層查詢則被標記為 primary
  • SUBQUERY/MATERIALIZED:SUBQUERY 表示在 select 或 where 列表中包含了子查詢,MATERIALIZED表示 where 後面 in 條件的子查詢
  • UNION:表示 union 中的第二個或後面的 select 語句
  • UNION RESULT:union 的結果

對於 UNION 和 UNION RESULT 可以通過下面的例子展現:

EXPLAIN
SELECT * FROM users WHERE id IN(1, 2)
UNION
SELECT * FROM users WHERE id IN(3, 4);

執行計劃的 table

查詢涉及到的表。

  • 直接顯示錶名或者表的別名
  • <unionM,N> 由 ID 為 M,N 查詢 union 產生的結果
  • <subqueryN> 由 ID 為 N 查詢產生的結果

執行計劃的 type 

訪問類型,SQL 查詢優化中一個很重要的指標,結果值從好到壞依次是:system > const > eq_ref > ref > range > index > ALL。

  • system:系統表,少量數據,往往不需要進行磁盤IO
  • const:常量連接
  • eq_ref:主鍵索引(primary key)或者非空唯一索引(unique not null)等值掃描
  • ref:非主鍵非唯一索引等值掃描
  • range:範圍掃描
  • index:索引樹掃描
  • ALL:全表掃描(full table scan)

下面通過舉例說明。

system

explain select * from mysql.time_zone;

上例中,從系統庫 MySQL 的系統表 time_zone 里查詢數據,訪問類型為 system,這些數據已經加載到內存里,不需要進行磁盤 IO,這類掃描是速度最快的。

explain select * from (select * from user where id=1) tmp;

再舉一個例子,內層嵌套(const)返回了一個臨時表,外層嵌套從臨時表查詢,其掃描類型也是 system,也不需要走磁盤 IO,速度超快。

const 

數據準備:

CREATE TABLE `user` (
  `id` int(11) NOT NULL,
  `NAME` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert into user values(1,'shenjian');
insert into user values(2,'zhangsan');
insert into user values(3,'lisi');
explain select * from user where id=1;

const 掃描的條件為: 

  1. 命中主鍵(primary key)或者唯一(unique)索引
  2. 被連接的部分是一個常量(const)值 

如上例,id 是 主鍵索引,連接部分是常量1。

eq_ref

數據準備:

CREATE TABLE `user` (
  `id` int(11) NOT NULL,
  `NAME` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert into user values(1,'shenjian');
insert into user values(2,'zhangsan');
insert into user values(3,'lisi');

CREATE TABLE `user_ex` (
  `id` int(11) NOT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert into user_ex values(1,18);
insert into user_ex values(2,20);
insert into user_ex values(3,30);
insert into user_ex values(4,40);
insert into user_ex values(5,50);
EXPLAIN SELECT * FROM USER,user_ex WHERE user.id=user_ex.id;

eq_ref 掃描的條件為,對於前表的每一行(row),后表只有一行被掃描。 

再細化一點:  

  1. join 查詢
  2. 命中主鍵(primary key)或者非空唯一(unique not null)索引
  3. 等值連接;

如上例,id 是主鍵,該 join 查詢為 eq_ref 掃描。

ref

數據準備:

CREATE TABLE `user` (
  `id` int(11) DEFAULT NULL,
  `name` varchar(20) DEFAULT NULL,
  KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert into user values(1,'shenjian');
insert into user values(2,'zhangsan');
insert into user values(3,'lisi');

CREATE TABLE `user_ex` (
  `id` int(11) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert into user_ex values(1,18);
insert into user_ex values(2,20);
insert into user_ex values(3,30);
insert into user_ex values(4,40);
insert into user_ex values(5,50);
EXPLAIN SELECT * FROM USER,user_ex WHERE user.id=user_ex.id;

如果把上例 eq_ref 案例中的主鍵索引,改為普通非唯一(non unique)索引。就由 eq_ref 降級為了 ref,此時對於前表的每一行(row),后表可能有多於一行的數據被掃描。

select * from user where id=1;

當 id 改為普通非唯一索引后,常量的連接查詢,也由 const 降級為了 ref,因為也可能有多於一行的數據被掃描。

ref 掃描,可能出現在 join 里,也可能出現在單表普通索引里,每一次匹配可能有多行數據返回,雖然它比 eq_ref 要慢,但它仍然是一個很快的 join 類型。

range

數據準備:

CREATE TABLE `user` (
  `id` int(11) NOT NULL,
  `name` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert into user values(1,'shenjian');
insert into user values(2,'zhangsan');
insert into user values(3,'lisi');
insert into user values(4,'wangwu');
insert into user values(5,'zhaoliu');
explain select * from user where id between 1 and 4;
explain select * from user where id in(1,2,3);
explain select * from user where id > 3;

range 掃描就比較好理解了,它是索引上的範圍查詢,它會在索引上掃碼特定範圍內的值。

像上例中的 between,in,> 都是典型的範圍(range)查詢。

index

explain count (*) from user;

如上例,id 是主鍵,該 count 查詢需要通過掃描索引上的全部數據來計數,它僅比全表掃描快一點。

ALL 

數據準備:

CREATE TABLE `user` (
  `id` int(11) DEFAULT NULL,
  `name` varchar(20) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert into user values(1,'shenjian');
insert into user values(2,'zhangsan');
insert into user values(3,'lisi');

CREATE TABLE `user_ex` (
  `id` int(11) DEFAULT NULL,
  `age` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert into user_ex values(1,18);
insert into user_ex values(2,20);
insert into user_ex values(3,30);
insert into user_ex values(4,40);
insert into user_ex values(5,50);
explain select * from user,user_ex where user.id=user_ex.id;

如果 id 上不建索引,對於前表的每一行(row),后表都要被全表掃描。

文章中,這個相同的 join 語句出現了三次:

  1. 掃描類型為 eq_ref,此時 id 為主鍵
  2. 掃描類型為 ref,此時 id 為非唯一普通索引
  3. 掃描類型為 ALL,全表掃描,此時id上無索引

有此可見,建立正確的索引,對數據庫性能的提升是多麼重要。

總結 

  1. explain 結果中的 type 字段,表示(廣義)連接類型,它描述了找到所需數據使用的掃描方式;
  2. 常見的掃描類型有:system>const>eq_ref>ref>range>index>ALL,其掃描速度由快到慢;
  3. 各類掃描類型的要點是:
    1. system 最快:不進行磁盤 IO
    2. const:PK 或者 unique 上的等值查詢
    3. eq_ref:PK 或者 unique 上的 join 查詢,等值匹配,對於前表的每一行,后表只有一行命中
    4. ref:非唯一索引,等值匹配,可能有多行命中
    5. range:索引上的範圍掃描,例如:between、in、>
    6. index:索引上的全集掃描,例如:InnoDB 的 count
    7. ALL 最慢:全表掃描
  1. 建立正確的索引,非常重要;
  2. 使用 explain 了解並優化執行計劃,非常重要;

執行計劃 possible_keys

查詢過程中有可能用到的索引。

執行計劃 key

實際使用的索引,如果為 NULL ,則沒有使用索引。

執行計劃 rows

根據表統計信息或者索引選用情況,大致估算出找到所需的記錄所需要讀取的行數。

執行計劃 filtered 

表示返回結果的行數占需讀取行數的百分比, filtered 的值越大越好。

執行計劃 Extra 

十分重要的額外信息。

  • Using filesort:MySQL 對數據使用一個外部的文件內容進行了排序,而不是按照表內的索引進行排序讀取。
  • Using temporary:使用臨時表保存中間結果,也就是說 MySQL 在對查詢結果排序時使用了臨時表,常見於order by 或 group by。
  • Using index:表示 SQL 操作中使用了覆蓋索引(Covering Index),避免了訪問表的數據行,效率高。
  • Using index condition:表示 SQL 操作命中了索引,但不是所有的列數據都在索引樹上,還需要訪問實際的行記錄。
  • Using where:表示 SQL 操作使用了 where 過濾條件。
  • Select tables optimized away:基於索引優化 MIN/MAX 操作或者 MyISAM 存儲引擎優化 COUNT(*) 操作,不必等到執行階段再進行計算,查詢執行計劃生成的階段即可完成優化。
  • Using join buffer (Block Nested Loop):表示 SQL 操作使用了關聯查詢或者子查詢,且需要進行嵌套循環計算。

下面通過舉例說明。

數據準備:

CREATE TABLE `user` (
  `id` int(11) NOT NULL,
  `name` varchar(20) DEFAULT NULL,
  `sex` varchar(5) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

insert into user values(1, 'shenjian','no');
insert into user values(2, 'zhangsan','no');
insert into user values(3, 'lisi', 'yes');
insert into user values(4, 'lisi', 'no');

數據說明:

用戶表:id 主鍵索引,name 普通索引(非唯一),sex 無索引。

四行記錄:其中 name 普通索引存在重複記錄 lisi。

Using filesort

explain select * from user order by sex;

 

Extra 為 Using filesort 說明,得到所需結果集,需要對所有記錄進行文件排序。

這類 SQL 語句性能極差,需要進行優化。

典型的,在一個沒有建立索引的列上進行了 order by,就會觸發 filesort,常見的優化方案是,在 order by 的列上添加索引,避免每次查詢都全量排序。

Using temporary

explain select * from user group by name order by sex;

Extra 為 Using temporary 說明,需要建立臨時表(temporary table)來暫存中間結果。

這類 SQL 語句性能較低,往往也需要進行優化。

典型的 group by 和 order by 同時存在,且作用於不同的字段時,就會建立臨時表,以便計算出最終的結果集。

臨時表存在兩種引擎,一種是 Memory 引擎,一種是 MyISAM 引擎,如果返回的數據在 16M 以內(默認),且沒有大字段的情況下,使用 Memory 引擎,否則使用 MyISAM 引擎。 

Using index

EXPLAIN SELECT id FROM USER;

Extra 為 Using index 說明,SQL 所需要返回的所有列數據均在一棵索引樹上,而無需訪問實際的行記錄。

這類 SQL 語句往往性能較好。

Using index condition

explain select id, name, sex from user where name='shenjian';

Extra 為 Using index condition 說明,確實命中了索引,但不是所有的列數據都在索引樹上,還需要訪問實際的行記錄。

這類 SQL 語句性能也較高,但不如 Using index。

Using where

explain select * from user where sex='no';

Extra 為 Using where 說明,查詢的結果集使用了 where 過濾條件,比如上面的 SQL 使用了 sex = 'no' 的過濾條件

Select tables optimized away

EXPLAIN SELECT MAX(id) FROM USER;

 

比如上面的語句查詢 id 的最大值,因為 id 是主鍵索引,根據 B+Tree 的結構,天然就是有序存放的,所以不需要等到執行階段再進行計算,查詢執行計劃生成的階段即可完成優化。

Using join buffer (Block Nested Loop)

explain select * from user where id in (select id from user where sex='no');

Extra 為 Using join buffer (Block Nested Loop) 說明,需要進行嵌套循環計算。內層和外層的 type 均為 ALL,rows 均為4,需要循環進行4*4次計算。

這類 SQL 語句性能往往也較低,需要進行優化。

典型的兩個關聯表 join,關聯字段均未建立索引,就會出現這種情況。常見的優化方案是,在關聯字段上添加索引,避免每次嵌套循環計算。

參考 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

分類
發燒車訊

電腦屏幕太小不夠用?這有妙招!

前段時間跟大家探討了 Vim 的顏色方案的話題,取得了不錯的反響,大家可以點擊以下鏈接回顧那篇文章:

今天我們來介紹 Vim 的分屏功能

為什麼需要分屏功能?其實需求場合有很多。比如,我現在屏幕很大,但我們的代碼一般是左對齊,右邊很空,這樣我們就可以通過分屏來充分利用右邊的屏幕。再如,我現在想同時查看多個文檔,除了打開多個終端外,我們還可以通過分屏來達到我們的目的。

當然類似的場合還有很多,只要我們充分挖掘,肯定能挖掘出更多需求。

下面我們就來詳細介紹 Vim 的分屏操作。

分屏功能基本操作

首先我們隨便打開一個代碼文件。為了方便演示,代碼長度越長越好。

vim test.c

現在讓我們將界面分成左右兩部分。首先我們按 ctrl+w ,緊接着按 v 。這樣操作之後,屏幕就一分為二了,如下圖示:

如果我們想要三等分怎麼操作?很簡單,在上面的基礎之上,我們再次執行一遍上面的操作,屏幕就三等分了。

如果你覺得這樣操作太麻煩,我們還可以通過在末行模式執行以下命令達到同樣的效果:

:vsplit

既然是命令,那就肯定有縮寫:

:vsp

簡直簡單到離譜…來點有水平的~讓我們從頭開始,這次我們將屏幕進行橫向分割。首先我們在末行模式下運行以下命令:

:split

同樣的,我們也有縮寫命令:

:sp

這個功能也可通過鍵盤組合鍵實現。對於水平分割來講,先按 ctrl + w ,然後按 s 。同樣,所有這些字母都是小寫的,並且是英文輸入狀態。

分屏之間切換

如前文所言,分屏在很多場景下非常有用,但是,你如果不能從一個分屏切換到另一個分屏,那這種拆分視圖就完全沒意義了。下面讓我給大家展示如何從一個分屏切換另一個分屏。

在這裏,我設置了同一文件的4個分割視圖。

剛開始時,光標位於第一個分屏。現在,假如我們要切換到右側分屏,我們需要先按 ctrl + w ,然後按 l

同樣地,假如我們要切換到左側窗口,需要先按 ctrl + w ,然後按 h

如果你是進行橫向分割屏幕的,那麼就只能上下移動光標。要切換到上面的分屏,需要先按 ctrl + w ,然後按 k

同樣地,如果想要切換到下面的分屏,那麼就需要先按 ctrl + w,然後按 j

在不同分屏下進行編輯

到此為止,我相信大家已經學會了怎麼進行分屏操作了。那分完屏,我們怎麼在這些分屏下進行文本編輯呢?其實,每個分屏都可以視為一個完整的 Vim 窗口,我們平常怎麼編輯的,就怎樣去編輯文檔。

複製及粘貼操作

與未分屏是基本無差的,大家可以在從一個分屏里複製一段文本,再切換到另一個分屏進行粘貼。操作都是一樣的,只是需要在不同分屏里切換而已。

改變分屏尺寸

默認情況下,Vim 是按等分進行分屏操作的。如果我們想最大化/最小化某個分屏,要如何操作?

如果要將當前窗口加寬到最大尺寸,需要先按 ctrl + w ,然後按 |(注意:不是小寫 L ,是與或非的那個與 | )。

如果你想把當前窗口高度加高到最大尺寸,那麼需要使用 ctrl + w ,然後使用 **_** 。

那如果想要重置所有分割窗口的大小,那麼使用 ctrl+w ,然後按 =

默認情況下,Vim 在進行分屏操作時,每個分屏是等寬或等高的。如果要自定義分屏的寬度,大家可以使用以下結構:

:<width> vsp

同樣地,對於水平分割而言,可以使用類似結構自定義高度:

:<height> sp

在同一個 Vim 窗口下打開多個不同文件

目前為止,所有的 Vim 分屏都是同一個文件的副本,但在很多情況下,我們需要打開多個不同的文件。我們可以將 Vim 窗口進行分屏,再在不同的分屏里打開不同的文件。

如何在 Vim 中打開一個新文件?我們可以使用以下命令:

:e<path_to_file>/filename.extension

例如,我們想要在一個全新的 Vim 實例中打開 vimrc,我們可以使用以下命令:

:e~/.vimrc

打開 vimrc 之後,我們想要將屏幕水平切分並打開一個新文件,可以使用以下命令:

:sp<file_path>

而對於垂直分割屏幕,使用的也是類似的結構:

:vsp<file_path>

小結

Vim 分屏講到這裏就要跟大家告一段落了。這種操作還是比較有趣,並且十分實用。

本文介紹了 Vim 分屏的一些基本操作及編輯方法,合理利用這個功能可以使我們更加高效使用電腦屏幕,提高我們的效率。
—————–

我是良許,世界500強外企 Linux 開發工程師,專業生產 Linux 乾貨。歡迎關注我的公眾號「良許Linux」,裏面分享了 Linux入門、基礎、進階 等系列教程,同時也有 Git、Vim、開源項目 等技術乾貨。公眾號後台回復「1024」獲取最新最全的技術資料,回復「入群」進入高手如雲技術交流群。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

※想要讓你的商品成為最夯、最多人討論的話題?網頁設計公司讓你強力曝光

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

分類
發燒車訊

python內置模塊collections介紹

目錄

python內置模塊collections介紹

collections是Python內建的一個集合模塊,提供了許多有用的集合類。

1、namedtuple

python提供了很多非常好用的基本類型,比如不可變類型tuple,我們可以輕鬆地用它來表示一個二元向量。

>>> v = (2,3) 

我們發現,雖然(2,3)表示出了一個向量的兩個坐標,但是,如果沒有額外說明,又很難直接看出這個元組是用來表示一個坐標的。

為此定義一個class又小題大做了,這時,namedtuple就派上用場了。

>>> from collections import namedtuple
>>> Vector = namedtuple('Vector', ['x', 'y'])
>>> v = Vector(2,3)
>>> v.x
2
>>> v.y
3

namedtuple是一個函數,它用來創建一個自定義的tuple對象,並且規定了tuple元素的個數,並可以用屬性而不是索引來引用tuple的某個元素。

這樣一來,我們用namedtuple可以很方便地定義一種數據類型,它具備tuple的不變性,又可以根據屬性來引用,使用十分方便。

我們可以驗證創建的Vector對象的類型。

>>> type(v)
<class '__main__.Vector'>

>>> isinstance(v, Vector)
True

>>> isinstance(v, tuple)
True 

類似的,如果要用坐標和半徑表示一個圓,也可以用namedtuple定義:

>>> Circle = namedtuple('Circle', ['x', 'y', 'r'])
# namedtuple('名稱', [‘屬性列表’])

2、deque

在數據結構中,我們知道隊列和堆棧是兩個非常重要的數據類型,一個先進先出,一個後進先出。在python中,使用list存儲數據時,按索引訪問元素很快,但是插入和刪除元素就很慢了,因為list是線性存儲,數據量大的時候,插入和刪除效率很低。

deque是為了高效實現插入和刪除操作的雙向鏈表結構,非常適合實現隊列和堆棧這樣的數據結構。

>>> from collections import deque
>>> deq = deque([1, 2, 3])
>>> deq.append(4)
>>> deq
deque([1, 2, 3, 4])
>>> deq.appendleft(5)
>>> deq
deque([5, 1, 2, 3, 4])
>>> deq.pop()
4
>>> deq.popleft()
5
>>> deq
deque([1, 2, 3])

deque除了實現list的append()和pop()外,還支持appendleft()和popleft(),這樣就可以非常高效地往頭部添加或刪除元素。

3、defaultdict

使用dict字典類型時,如果引用的key不存在,就會拋出KeyError。如果希望Key不存在時,返回一個默認值,就可以用defaultdict。

>>> from collections import defaultdict
>>> dd = defaultdict(lambda: 'defaultvalue')
>>> dd['key1'] = 'a'
>>> dd['key1']
'a'
>>> dd['key2'] # key2未定義,返回默認值
'defaultvalue'

注意默認值是調用函數返回的,而函數在創建defaultdict對象時傳入。

除了在Key不存在時返回默認值,defaultdict的其他行為跟dict是完全一樣的。

4、OrderedDict

使用dict時,key是無序的。在對dict做迭代時,我們無法確定key的順序。

但是如果想要保持key的順序,可以用OrderedDict。

>>> from collections import OrderedDict
>>> d = dict([('a', 1), ('b', 2), ('c', 3)])
>>> d # dict的Key是無序的
{'a': 1, 'c': 3, 'b': 2}
>>> od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
>>> od # OrderedDict的Key是有序的
OrderedDict([('a', 1), ('b', 2), ('c', 3)])

注意,OrderedDict的key會按照插入的順序排列,不是key本身排序

>>> od = OrderedDict()
>>> od['z'] = 1
>>> od['y'] = 2
>>> od['x'] = 3
>>> list(od.keys()) # 按照插入的Key的順序返回
['z', 'y', 'x']

OrderedDict可以實現一個FIFO(先進先出)的dict,當容量超出限制時,先刪除最早添加的key。

from collections import OrderedDict

class LastUpdatedOrderedDict(OrderedDict):

    def __init__(self, capacity):
        super(LastUpdatedOrderedDict, self).__init__()
        self._capacity = capacity

    def __setitem__(self, key, value):
        containsKey = 1 if key in self else 0
        if len(self) - containsKey >= self._capacity:
            last = self.popitem(last=False)
            print('remove:', last)
        if containsKey:
            del self[key]
            print('set:', (key, value))
        else:
            print('add:', (key, value))
        OrderedDict.__setitem__(self, key, value)

5、ChainMap

ChainMap可以把一組dict串起來並組成一個邏輯上的dict。ChainMap本身也是一個dict,但是查找的時候,會按照順序在內部的dict依次查找。

什麼時候使用ChainMap最合適?舉個例子:應用程序往往都需要傳入參數,參數可以通過命令行傳入,可以通過環境變量傳入,還可以有默認參數。我們可以用ChainMap實現參數的優先級查找,即先查命令行參數,如果沒有傳入,再查環境變量,如果沒有,就使用默認參數。

下面的代碼演示了如何查找user和color這兩個參數。

from collections import ChainMap
import os, argparse

# 構造缺省參數:
defaults = {
    'color': 'red',
    'user': 'guest'
}

# 構造命令行參數:
parser = argparse.ArgumentParser()
parser.add_argument('-u', '--user')
parser.add_argument('-c', '--color')
namespace = parser.parse_args()
command_line_args = { k: v for k, v in vars(namespace).items() if v }

# 組合成ChainMap:
combined = ChainMap(command_line_args, os.environ, defaults)

# 打印參數:
print('color=%s' % combined['color'])
print('user=%s' % combined['user'])

沒有任何參數時,打印出默認參數:

$ python3 use_chainmap.py 
color=red
user=guest

當傳入命令行參數時,優先使用命令行參數:

$ python3 use_chainmap.py -u bob
color=red
user=bob

同時傳入命令行參數和環境變量,命令行參數的優先級較高:

$ user=admin color=green python3 use_chainmap.py -u bob
color=green
user=bob

6、Counter

Counter是一個簡單的計數器,例如,統計字符出現的個數:

from collections import Counter
>>> s = 'abbcccdddd'
>>> Counter(s)
Counter({'d': 4, 'c': 3, 'b': 2, 'a': 1})

Counter實際上也是dict的一個子類。

7、小結

collections模塊提供了一些有用的集合類,可以根據需要選用。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

※評比南投搬家公司費用收費行情懶人包大公開

分類
發燒車訊

【從今天開始好好學數據結構01】數組

面試的時候,常常會問數組和鏈表的區別,很多人都回答說,“鏈表適合插入、刪除,時間複雜度O(1);數組適合查找,查找時間複雜度為O(1)”。實際上,這種表述是不準確的。數組是適合查找操作,但是查找的時間複雜度並不為O(1)。即便是排好序的數組,你用二分查找,時間複雜度也是O(logn)。所以,正確的表述應該是,數組支持隨機訪問,根據下標隨機訪問的時間複雜度為O(1)。

每一種編程語言中,基本都會有數組這種數據類型。不過,它不僅僅是一種編程語言中的數據類型,還是一種最基礎的數據結構。儘管數組看起來非常基礎、簡單,但是我估計很多人都並沒有理解這個基礎數據結構的精髓。在大部分編程語言中,數組都是從0開始編號的,但你是否下意識地想過,為什麼數組要從0開始編號,而不是從1開始呢? 從1開始不是更符合人類的思維習慣嗎?帶着這個問題來學習接下來的內容,帶着問題去學習往往效果會更好!!!

什麼是數組?我估計你心中已經有了答案。不過,我還是想用專業的話來給你做下解釋。數組(Array)是一種線性表數據結構。它用一組連續的內存空間,來存儲一組具有相同類型的數據。這個定義里有幾個關鍵詞,理解了這幾個關鍵詞,我想你就能徹底掌握數組的概念了。下面就從我的角度分別給你“點撥”一下。

第一是線性表(Linear List)。顧名思義,線性表就是數據排成像一條線一樣的結構。每個線性表上的數據最多只有前和后兩個方向。其實除了數組,鏈表、隊列、棧等也是線性表結構。而與它相對立的概念是非線性表,比如二叉樹、堆、圖等。之所以叫非線性,是因為,在非線性表中,數據之間並不是簡單的前後關係。

第二個是連續的內存空間和相同類型的數據。正是因為這兩個限制,它才有了一個堪稱“殺手鐧”的特性:“隨機訪問”。但有利就有弊,這兩個限制也讓數組的很多操作變得非常低效,比如要想在數組中刪除、插入一個數據,數組為了保持內存數據的連續性,會導致插入、刪除這兩個操作比較低效,相反的數組查詢則高效

數組java代碼:

package array;

/**
 * 1) 數組的插入、刪除、按照下標隨機訪問操作;
 * 2)數組中的數據是int類型的;
 *
 * Author: Zheng
 * modify: xing, Gsealy
 */
public class Array {
    //定義整型數據data保存數據
    public int data[];
    //定義數組長度
    private int n;
    //定義中實際個數
    private int count;

    //構造方法,定義數組大小
    public Array(int capacity){
        this.data = new int[capacity];
        this.n = capacity;
        this.count=0;//一開始一個數都沒有存所以為0
    }

    //根據索引,找到數據中的元素並返回
    public int find(int index){
        if (index<0 || index>=count) return -1;
        return data[index];
    }

    //插入元素:頭部插入,尾部插入
    public boolean insert(int index, int value){
        //數組中無元素 

        //if (index == count && count == 0) {
        //    data[index] = value;
        //    ++count;
        //    return true;
        //}

        // 數組空間已滿
        if (count == n) {
            System.out.println("沒有可插入的位置");
            return false;
        }
        // 如果count還沒滿,那麼就可以插入數據到數組中
        // 位置不合法
        if (index < 0||index > count ) {
            System.out.println("位置不合法");
            return false;
        }
        // 位置合法
        for( int i = count; i > index; --i){
            data[i] = data[i - 1];
        }
        data[index] = value;
        ++count;
        return true;
    }
    //根據索引,刪除數組中元素
    public boolean delete(int index){
        if (index<0 || index >=count) return false;
        //從刪除位置開始,將後面的元素向前移動一位
        for (int i=index+1; i<count; ++i){
            data[i-1] = data[i];
        }
        //刪除數組末尾元素  這段代碼不需要也可以
        /*int[] arr = new int[count-1];
        for (int i=0; i<count-1;i++){
            arr[i] = data[i];
        }
        this.data = arr;*/

        --count;
        return true;
    }
    public void printAll() {
        for (int i = 0; i < count; ++i) {
            System.out.print(data[i] + " ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        Array array = new Array(5);
        array.printAll();
        array.insert(0, 3);
        array.insert(0, 4);
        array.insert(1, 5);
        array.insert(3, 9);
        array.insert(3, 10);
        //array.insert(3, 11);
        array.printAll();
    }
}

GenericArray數組代碼

public class GenericArray<T> {
    private T[] data;
    private int size;

    // 根據傳入容量,構造Array
    public GenericArray(int capacity) {
        data = (T[]) new Object[capacity];
        size = 0;
    }

    // 無參構造方法,默認數組容量為10
    public GenericArray() {
        this(10);
    }

    // 獲取數組容量
    public int getCapacity() {
        return data.length;
    }

    // 獲取當前元素個數
    public int count() {
        return size;
    }

    // 判斷數組是否為空
    public boolean isEmpty() {
        return size == 0;
    }

    // 修改 index 位置的元素
    public void set(int index, T e) {
        checkIndex(index);
        data[index] = e;
    }

    // 獲取對應 index 位置的元素
    public T get(int index) {
        checkIndex(index);
        return data[index];
    }

    // 查看數組是否包含元素e
    public boolean contains(T e) {
        for (int i = 0; i < size; i++) {
            if (data[i].equals(e)) {
                return true;
            }
        }
        return false;
    }

    // 獲取對應元素的下標, 未找到,返回 -1
    public int find(T e) {
        for ( int i = 0; i < size; i++) {
            if (data[i].equals(e)) {
                return i;
            }
        }
        return -1;
    }


    // 在 index 位置,插入元素e, 時間複雜度 O(m+n)
    public void add(int index, T e) {
        checkIndex(index);
        // 如果當前元素個數等於數組容量,則將數組擴容為原來的2倍
        if (size == data.length) {
            resize(2 * data.length);
        }

        for (int i = size - 1; i >= index; i--) {
            data[i + 1] = data[i];
        }
        data[index] = e;
        size++;
    }

    // 向數組頭插入元素
    public void addFirst(T e) {
        add(0, e);
    }

    // 向數組尾插入元素
    public void addLast(T e) {
        add(size, e);
    }

    // 刪除 index 位置的元素,並返回
    public T remove(int index) {
        checkIndexForRemove(index);

        T ret = data[index];
        for (int i = index + 1; i < size; i++) {
            data[i - 1] = data[i];
        }
        size --;
        data[size] = null;

        // 縮容
        if (size == data.length / 4 && data.length / 2 != 0) {
            resize(data.length / 2);
        }

        return ret;
    }

    // 刪除第一個元素
    public T removeFirst() {
        return remove(0);
    }

    // 刪除末尾元素
    public T removeLast() {
        return remove(size - 1);
    }

    // 從數組中刪除指定元素
    public void removeElement(T e) {
        int index = find(e);
        if (index != -1) {
            remove(index);
        }
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append(String.format("Array size = %d, capacity = %d \n", size, data.length));
        builder.append('[');
        for (int i = 0; i < size; i++) {
            builder.append(data[i]);
            if (i != size - 1) {
                builder.append(", ");
            }
        }
        builder.append(']');
        return builder.toString();
    }


    // 擴容方法,時間複雜度 O(n)
    private void resize(int capacity) {
        T[] newData = (T[]) new Object[capacity];

        for (int i = 0; i < size; i++) {
            newData[i] = data[i];
        }
        data = newData;
    }

    private void checkIndex(int index) {
        if (index < 0 || index > size) {
            throw new IllegalArgumentException("Add failed! Require index >=0 and index <= size.");
        }
    }

    private void checkIndexForRemove(int index) {
        if(index < 0 || index >= size) {
            throw new IllegalArgumentException("remove failed! Require index >=0 and index < size.");
        }
    }
}

到這裏,就回溯最初的問題:

從數組存儲的內存模型上來看,“下標”最確切的定義應該是“偏移(offset)”。前面也講到,如果用a來表示數組的首地址,a[0]就是偏移為0的位置,也就是首地址,a[k]就表示偏移k個type_size的位置,所以計算a[k]的內存地址只需要用這個公式:

a[k]_address = base_address + k * type_size

但是,如果數組從1開始計數,那我們計算數組元素a[k]的內存地址就會變為:

a[k]_address = base_address + (k-1)*type_size

對比兩個公式,我們不難發現,從1開始編號,每次隨機訪問數組元素都多了一次減法運算,對於CPU來說,就是多了一次減法指令。那你可以思考一下,類比一下,二維數組的內存尋址公式是怎樣的呢?有興趣的可以在評論區評論出來哦QAQ

數組作為非常基礎的數據結構,通過下標隨機訪問數組元素又是其非常基礎的編程操作,效率的優化就要盡可能做到極致。所以為了減少一次減法操作,數組選擇了從0開始編號,而不是從1開始。
不過我認為,上面解釋得再多其實都算不上壓倒性的證明,說數組起始編號非0開始不可。所以我覺得最主要的原因可能是歷史原因。

關於數組,它可以說是最基礎、最簡單的數據結構了。數組用一塊連續的內存空間,來存儲相同類型的一組數據,最大的特點就是支持隨機訪問,但插入、刪除操作也因此變得比較低效,平均情況時間複雜度為O(n)。在平時的業務開發中,我們可以直接使用編程語言提供的容器類,但是,如果是特別底層的開發,直接使用數組可能會更合適。

如果本文對你有一點點幫助,那麼請點個讚唄,謝謝~

最後,若有不足或者不正之處,歡迎指正批評,感激不盡!如果有疑問歡迎留言,絕對第一時間回復!

歡迎各位關注我的公眾號,一起探討技術,嚮往技術,追求技術,說好了來了就是盆友喔…

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

南投搬家費用,距離,噸數怎麼算?達人教你簡易估價知識!