WHAT'S NEW?
Loading...

胖子工程師辛酸史: 思考自身缺點

最近胖子突然對工作感到疲倦,他決定約大學時期的朋友們一起吃個午餐,因此他們到星巴克邊喝咖啡邊聊天....

一開始,由在外商公司工作的小明開場白問:『最近你們工作如何?』

胖子:『我還是老樣子,每天工作佔據大部分的時間,我都快累死了!』

小新:『唉~~我遇到難搞的專案經理,我已經三天沒睡覺了~~!這次工作完,我一定要好好休息,那小明你在外商過得如何?』

小明:『恩,我都能準時上下班,而且最近公司有意派我到國外出差!』

小新:『真好喔! 我每天累得像狗一樣,最討厭的是心機重的同事,功勞都被那些人搶去了!胖子,你同事相處起來如何?』

胖子:『不論在哪一間公司多多少少會遇到小人吧!所以,我盡量學習如何與這種人如何相處!』

小明點頭贊成胖子的話,然後說:『我們公司也有這樣的人,說實話我很少理那些人,與其將時間關注那些人的動態,還不如做好自己的事,甚至加強自己的技術!』

小新:『你們都怎樣加強自己的技術?目前我在小公司都沒人帶我,說實話我很害怕換工作.』

胖子:『恩,公司專案是不錯的實作經驗,目前我能照公司的時間表完成工作.最近我覺得程式架構不夠好,因此藉由重構程式碼來加強自己的技術.』

小明:『最近自學Design pattern和UML,並且將這些技術實作在公司專案.然而,我有些地方不是很了解,因此我最近考慮上一些課吧!』

小新一臉鬱悶看著小明說:『你這種做法只存在讓你準時上下班的公司吧!我每天都有做不完的事,哪有時間做這些阿!』

聽到這些話的小明搖搖頭後,他轉移話題跟小新和胖子聊著生活上的瑣事,輕鬆度過這次會面.

然而當胖子回到家後,他不禁反問自己為何與大學同學小明有如此大的差距?他開始回想這次談話,雖然他有不斷檢討自己程式的問題,然而他碰到相同問題好幾次,他才會主動讀相關書籍找出解決問題的最佳答案.說實話,他很不喜歡讀書,因此他經常無法清楚表達程式相關技術.


作者有話要說:

有一天,伐木工很高興得到工作,他第一天超過進度砍了很多樹,所以從老闆那邊得到讚揚,因此他為了報答老闆賞賜,他每天埋頭苦幹的工作,然而他砍樹的速度卻越來越慢,他感到很緊張不知道原因,然而當老闆看了他工作情況後,說:『你多久沒有磨利斧頭?』
同事曾經問我有關物件導向的問題,然而我卻無法給正確答案.那時的我只想程式寫多慢慢就會,然而,當我讀到以上的故事後,我才知道遇到問題不是假裝不知道,而是應該讀相關書籍找出解決問題的最佳答案.換句話說,寫程式就像斧頭一樣,當你根據公司需求寫了一個又一個程式時,不要忘記隨時增進自己的技術,要不然就像鈍斧頭砍樹一樣,你不但做事越來越沒有效率,而且無法成為專業人士.

這次胖子故事沒有忘記把自己的斧頭磨利,然而若要換到更好工作,我想遠遠是不夠.因為你要考慮目前公司的技術不一定是其他公司所要的.例如:Design pattern和UML並不是每個台灣的公司都有用此技術,然而這些技術在國外不但很普遍,而且也能加強自己的工作效率.換句話說,程式設計者應該使自己成為國際化人才,隨時準備下一個工作的技術.

Qt物件導向:建構子與解構子

Qt物件導向:什麼是類別主要簡單描述類別的組成。在C++11以前,類別主要會用到四個成員函數:
  • 建構子 (Constructor)
  • 三法則 (Rule of Three)
    • 解構子 (Destructors)
    • 複製建構子 (Copy Constructor)
    • 設定運算子 (Copy assignment operator )

當資料成員含有指標時對記憶體進行操作,建構子通常對指標資料成員配置記憶體位置,而解構子主要釋放此指標所佔用的記憶體

接下來,我將解釋此四個成員函數所代表的意義:

建構子

建構子必須與類別名稱相同,而且當你初始化類別產生物件時,建構子將自動地被呼叫.因此,建構子初始化類別的成員或對指標成員動態配置記憶體.此成員函數有以下特性:
  • 沒有回傳值 (Return type)
  • 允許重載 (Overloading) -可定義多個建構子
    • 默認建構子 (default) 是沒有輸入引數 (arguments) 。因此,當你在標頭檔沒有定義建構子成員函數時,編譯器將自動產生。
    • classname::classname()
      {
      }
      

  • 若在標頭檔定義建構子時,加入修飾語 explicit,則限制此類別的所呼叫的建構子。


解構子

解構子主要由類別名稱和~所構成,然而此成員函數主要在消滅物件前釋放之前所配置的記憶體.因此,當在建構子為指標動態配置記憶體時(i.e. new),別忘記要在解構子釋放此記憶體(i.e. delete)。

classname::~classname()
{
}
  • 沒有回傳值 (Return type)
  • 不允許重載 (Overloading) - 唯一
  • 預設不是虛函數

注意事項

    • 解構子絕對不能拋出異常。若解構子調用拋出異常函數,請捕捉此異常做相應的處理。

      線上測驗:http://quiz.geeksforgeeks.org/c-plus-plus/destructors/

       物件什麼時候會被消滅?

      • 在程式結束之前,所有物件所佔用的靜態記憶體位址(i.e.全域變數)將會被釋放.
      • 當使用new初始化類別產生物件時,請記得使用delete歸還所佔用的記憶體.
      • 當區域物件變數超出作用域範圍,例如在成員函數使用區域物件變數時,當出現return指令時,程式將自動消滅此物件.

      Reference:

      1. Effective C++

      C++資料結構與演算法: 單向鏈結串列(下)

      上一篇簡單說明如何將標頭檔轉換成UML類別圖,而這篇將主要解釋有關鏈結串列的刪除,加入和顯示,如以下所示:
      • showList():顯示鏈結串列所有資料
      • append(QString addData):在鏈結串列的後面加入資料
      • remove(QString delData):刪除鏈結串列的某一筆資料


      成員函數showList()


      主要顯示鏈結串列內的字串內容,利用迴圈判斷curr的指標結構變數是否為NULL來走訪鏈結串列,這裡使用C函數printf印出串列資料

      void dstringList::showList()
      {
          curr=head;
          while(curr!=NULL)
          {
              printf("%S\n",curr->data.constData());
              curr=curr->next;
          }
      }


      成員函數append(QString addData)


      圖二.在鏈結串列後面加入資料

      如圖二所示,此函數主要在鏈結串列後面加入新結構變數資料.首先,我先宣告指標結構變數node,並且在資料成員的data要加入字串資料和指標變數next為NULL .然後,走訪鏈結串列找到資料尾端後,將此尾端的資料成員next指向新加入的結構變數node.

      void dstringList::append(QString addData)
      {
          nodeptr node=new strNode;
          node->data=addData;
          node->next=NULL;
      
          if(head!=NULL)
          {
              curr=head;
              while(curr->next!=NULL)
              {
                  curr=curr->next;
              }
              curr->next=node;
          }
          else head=node;
      }
      

      成員函數remove(QString delData)


      圖三.刪除結構變數含有Taipei的資料
      此函數主要刪除鏈結串列含有資料delData的結構變數strNode.假設要刪除串列中字串為Taipei,詳細流程如以下說明:

      • 利用迴圈在確認指向下一個結構變數不為NULL目前結構變數的資料不為Taipei下走訪鏈結串列.
        • curr:紀錄目前的結構變數記憶體位址.
        • temp:則紀錄上一個結構變數記憶體位址.
      • 當找到所要刪除結構變數記憶體位址時,delPtr將記錄此位址後利用delete釋放此記憶體位址.換句話說,刪除在記憶體刪除含有Taipei的結構變數.
      • 最後,curr將指向下一個含有Xinbei的結構變數,然後temp的結構變數指標將指向此結構變數,如圖三所示.


      void dstringList::remove(QString delData)
      {
          nodeptr delPtr=NULL;
          temp=head;
          curr=head;
          while(curr!=NULL&&curr->data!=delData)
          {
              temp=curr;
              curr=curr->next;
          }
          if(curr==NULL)
          {
              printf("%S was not in the List\n",delData.constData());
              delete delPtr;
          }
          else
          {
              delPtr=curr;
              curr=curr->next;
              temp->next=curr;
              if(temp==head)
              {
                 head=head->next;
                 temp=NULL;
              }
              delete delPtr;
          }
      }
      


      壓抑的台灣:主動與別人合作

      圖一.團體合作重要性

      最近,我都活動在小圈子,使我眼界越來越狹隘,因此我開始去接觸人群去了解目前業界狀況.然而,王品戴勝益說『月薪五萬不要存錢別儲蓄』,並且將錢拓展人際關係,我認為對大學新鮮人並不適用.說實話,大部分新鮮人未工作前沒有很清楚職涯規劃和方向,因此此時花錢經營人脈有點亂槍打鳥,尤其對於程式設計者.我認為與其經營人脈不如學習如何跟人合作,因為在合作過程中你才更清楚如何經營人與人之間關係,吃飯聊天你只看到人的表面,而當你此人合作時,你才能辨認他是否值得交的人.

      為什麼要參與團體合作?如圖一所示,編織的工作可以被拆成好幾個小工作,然後每個部分都有所負責的人,最後有效率地完成產品.因此,沒有一個公司會想要雇用與人合作有障礙的人,因為每個產品發表背後都有一大群人共同開發,所以當你想換工作時,大部分的面試官都會詢問離職原因看你是否與前同事相處不愉快.有一次,有人問我對物件導向的看法,一開始我講很多理論和實作層面,然而他不是要這些答案,他告訴我說:『物件導向主要方便與人合作或分配工作,每個人有自己要開發的類別,而團隊可以很容易將這些類別組合成一個系統.』.換句話說,學習不應該只想到理論部分,而是也要思考生活上的應用.總而言之,各行各業都存在合作關係,因此不要再專注個人得失,而是考慮你可以在這團體貢獻什麼

      事實上,在台灣的教育系統,大部分學校很少教學生如何與別人合作,尤其碩博士生.到目前為止,我所看到碩博士生只專注自己的研究,反而很少看到這些學生與不同領域的人合作,甚至同領域之間交流只互相討論各自做了什麼.舉例來說,當專案經常出現重複的程式碼,這也就代表團隊之間沒有很好合作關係,程式設計者各自寫自己的程式,因此團隊之間經常將時間浪費在開發同樣的東西.還有,每個人都在寫程式時有各自啟發和成長,在交流時請不要強迫別人接受你的意見,而是分享各自想法後反省自己不足的部分.換句話說,若將重複的部分模組化讓其他人使用,不但能解省時間,而且也通過交流找出自己不足的部分.

      在讀大學的時候,我最多跟同領域的人合作一起完成大學專題,因此當我出去工作時第一個遇到難關就是如何跟非技術人員講述所開發的內容,尤其是不懂技術的專案經理.說實話,與這些人相處時,我不但能發現自己的缺點,而且也發現職場上不像寫程式來的簡單.總而言之,職場人際關係不像程式有標準答案,因此增強自己的能力不要忘了也要學習如何與人相處.


      胖子工程師辛酸史: 時間分配

      上次,雖然胖子沒有成功說服老闆將重構排入工作時程,他也沒有將全部心思花在說服老闆上面,只有在上下班途中思考說服老闆的方法.

      最近,胖子突然覺得重構是一個魯莽的方案,一方面他不確定有沒有時間準備這件事,另一方面他也沒有規劃重構所需花的時間.

      因此,胖子開始思考找出多餘時間,他先試試看重構所需花的時間,所以他開始檢討自己日常浪費了多少時間.

      有一天,專案經理的小弟A跑來找胖子....

      小弟A:『那個我們辦公室的電腦有點問題,經理叫你過去幫忙看看』

      胖子心想時間就是被你們所浪費掉,因此他面帶苦惱說:『抱歉,我手上還忙著老闆交代的事,要不然你請新進的工讀生幫忙看看吧!』

      小弟A皺著眉頭說:『但經理指定要你去耶!而且工讀生做事效率很慢耶!』

      胖子嘆了一口起後說:『沒辦法,經理上次一直說我們資訊組做事效率很差,讓老闆很關注我們資訊組,因此我們盡可能節省時間提升工作時間.不聊了,我還要繼續忙!』

      聽完胖子說完話後,小弟只好帶著工讀生回去自己辦公室,然而問題卻沒有專案經理想得那麼嚴重,工讀生大概花一了小時就解決問題,因此胖子更清楚有些話不可信,畢竟人難免將問題誇大,因此先將事情交給工讀生處理,不但節省自己時間,而且也才真正知道問題的嚴重性.

      又有一天,胖子正在修程式架構時,專案經理打給他....

      專案經理:『胖子,剛才客戶email給我程式有bug,你趕快把錯誤修正,並且上更新檔!』

      胖子:『知道了!請問什麼時候要?』

      專案經理:『當然越快越好!幸好那個人跟我很熟,他說趁更上層還沒發現前,叫你趕快修正!』

      胖子心想事情應該沒有你說得那麼誇張,他只好說:『那你可以請你寄副本信件給我』

      雖然專案經理說得很急,胖子仍然繼續之前他的工作,因為他思考一下目前工作大概中午以前就完成,因此他打算下午才處理這件事.因為他看了信件以後評估這件事只需要下午就可以完成.還有,他已經問專案經理什麼時間要,然而專案經理卻給模糊答案,每個人對時間定義有所不同,因此專案經理竟然沒有給他明確時間,就表示這件事沒有馬上處理的必要性.

      作者有話要說:

      其實,程式設計者最忌緯思緒被打斷,然而旁邊的人很少會體諒這一點,大部分人都把自己的利益擺第一優先,因此他也不管會不會干擾其他人的工作,他就直接打電話派新任務給工程師.說實話,交派任務並不讓人厭惡,而是自己搞不清截止期限,然後拿更上層的人壓你催你把工作做完的人,而這樣作為是非常不負責的行為.

      因此,我就利用胖子的故事告訴你有些人的話聽聽就好,而是要自己衡量這件事是否需要馬上去處理.畢竟,馬上處理另一件事不但需要花更多時間做轉換,而且也影響自己工作效率.

      壓抑的台灣: 請正視技術價值

      圖一.價值與錢的關係(source:managingamericans)

      最近看了千田琢哉的『就算被討厭,也要勇敢說出來的100句話』,這本書讓我了解話語的重要性,或許會讓人討厭你,然而若不敢說出來,你不知不覺浪費你的時間和犧牲你的無形資產.其中最貼切的話語是『你可以給便宜多少?一分錢也不行』,你或許想問為何不讓人殺價呢?作者給的答案是即使你給對方優惠,對方也不會心存感激.接下來,我想利用小故事來講述千田琢哉的概念.

      我曾經看過某公司沾沾自喜提供給政府便宜又大碗的系統,甚至當政府刪到他的預算,他還很高興說:『至少還有計畫可以接,就讓他們砍吧!』或許,老闆很貼心為政府著想,然而底下的員工卻感到不貼心,甚至認為自己的福利被壓榨.此公司的技術的確比其他公司好,然而他卻從不正視自己技術價值,反而只抱怨其他公司的諂媚.事實上,對於陌生人來說,由於他不瞭解你的公司,因此他只用價格評斷你產品的價值.爭取經費不是很庸俗的事,而是合理的經費公司才能給員工好福利和改善工作環境.因此,此公司為了給政府方便犧牲自身的福利,然而對方沒心存感激幫他們爭取到合理預算,還犧牲到員工該有的福利.

      還有,台灣新聞經常讚揚某科技公司搶到蘋果訂單,然而台廠從蘋果身上得到的利潤卻只有2%,因此蘋果訂單真的有益於台灣上班族嗎?我朋友曾經跟我說過:『辛辛苦苦想出的產品卻被賤賣,而且薪水也一直不加薪,他為自己感到不值得!』因此,打價格戰不但催毀台灣技術人員的價值,甚至永遠停留代工產業,走不出自己的品牌.

      當你看到台廠接小米機的訂單,你有何感想?那時,我只想到台灣也淪為幫大陸代工,或許台灣有宏達電htc,然而市佔率遠遠輸掉大陸品牌聯想.還有,中國政府之前封鎖Google鬧得沸沸揚揚,或許你會想大陸是想控制言論自由,然而封鎖國外資訊產業進駐大陸,不但能讓本土產業穩定發展,甚至當公司壯大時有能力跟國外大廠競爭.由此可見,大陸也在積極擺脫代工產業,一方面他們有足夠的內需市場,另一方面也發展自有品牌進軍國際市場.

      總而言之,技術的價值應該與錢一樣處於平衡的關係,如圖一所示.若貶低技術價值,不但不會贏得該有尊重,而且也會使公司停滯不前.因為價格太低會傷到工程師的自尊心,甚至沒有人願意提出新創意幫助公司.因此,有些老闆當你批評台灣人草莓族,請思考和反省你自己公司,批評不會讓你吸引到好人才,只有反省才能讓公司成長.

      C++資料結構與演算法: 單向鏈結串列(中)

      上一篇簡單說明如何建立單向鏈結的結構變數,而這篇將解釋如何建立單向鏈結的類別,此類別有以下的功能:
      • 在串列的前面(prepend)增加資料
      • 在串列的後面(append)增加資料
      • 刪除串列的某一筆資料
      • 顯示串列所有資料

      可視化類別的標頭檔


      之前在UML之類別圖,我簡單解釋如何將標頭檔使用類別圖來表示,而這次類別dstringList不但含有結構變數strNode,而且還有指向結構變數的指標.
      • 若變數為指標,我們通常使用*或<<ptr>>來表示
      • 由於指標的定義為指向資料型別的變數,因此在UML圖呈現指標的含意,我們需使用Association的單向連結
      • 由於宣告多個指標變數nodeptr,而nodeptr與結構變數strNode有關,而在UML圖通常使用Containment來表示

      class dstringList
      {
      private:
          typedef struct strNode
          {
             QString data;
             strNode *next;
          }*nodeptr;
      
          nodeptr head;
          nodeptr curr;
          nodeptr temp;
      
      public:
          dstringList();
          void append(QString addData);
          void prepend(QString addData);
          void showList();
          void remove(QString delData);
      
      };
      

      圖一.dstringList的類別圖


      建構子 dstringList()

      建構子(constructor)是一個與類別名稱相同的特殊的資料成員,此成員只要產生類別的物件就會執行,所以主要用來初始化資料成員變數和配置所需的記憶體.因此,在此類別的建構子,我們需初始指標結構變數head, currtemp,要不然成員函數在對資料成員進行操作時,程式可能會產生無法預期的錯誤.


      dstringList::dstringList()
      {
          head=NULL;
          curr=NULL;
          temp=NULL;
      }
      
      

      Qt:類別圖範例 (待修)

      2015/02/05 增加UML類別圖:基本概念篇
      http://chenglearning.blogspot.tw/2015/02/classdiagramintro.html

      類別圖介紹


      最經常使用UML圖是類別圖(Class diagram),類別圖也可被稱作靜態圖(Static diagram).之前在建立存取資料庫的類別QSqlTableModel與QTableView連結使用類別圖來呈現類別的成員函數和資料成員,因此類別圖主要由以下的項目組成,如下圖所示:
      • 類別名稱: YTDBConnection
      • 資料成員:db
      • 成員函數:OpenDB(),CloseDB() 和getDataList(QStringList &dl_ist)
      圖一.YTDBConnection類別示意圖


      可視化類別的標頭檔

      class YTDBConnection
      {
      public:
          YTDBConnection();   //constructor
      public:
          bool OpenDB();  //Connect to my database "Taiwan"
          void CloseDB(); //Close database
          bool getData(QStringList &d_list); //get a list of the Taiwan city names from database
          bool getData(QTableView *srcTable,QString currentText);
      private:
          QSqlDatabase db;
      };
      

      如以上的程式碼所示,YTDBConnection.h描述此類別的屬性(attribute)和操作(operation),而我們想要將標頭檔轉換成類別圖,換句話說使用類別圖可視化(visualize)類別的標頭檔.畫類別圖主要有以下的注意事項:

      • 類別的相依性
        • Containment :通常用來描述鏈結串列,二元樹,關係陣列
        • Association :類別彼此都有著直接的關係
          • 單向連結(singly linked)
          • 雙向連結(double linked)


      Reference:

      1. Michael Hall, UML Class Diagrams 
      2. http://xoax.net/blog/category/uml/
      3. Qt教學與開發 
      4. http://chenglearning.blogspot.tw/p/qt.html

      胖子工程師辛酸史:職場衝突

      上次與工程師B談話,胖子試著讓公司接受資訊組對程式碼進行重構,然而私下與專案經理提過,他一聽就立刻回絕胖子的提議,並且質問胖子是否想偷懶,因此胖子與專案經理有一段不愉快的對談.

      而今天是胖子與工程師B向老闆提出FakeLemon企劃案,並且各自使用投影片向老闆報告,因此當他們報告完時,老闆皺著眉頭提出問題.

      老闆:"恩....目前看起來胖子的企劃案可行性比較高,但是為何你的企劃案有上次做的資料可視化功能,這不是上次已交貨的功能!"

      胖子:"老闆,這的確是之前的功能.然而這次企劃案主要幫助FakeLemon分析和開發客戶群,讓電腦自動推薦正確產品給客戶,我認為將之前的功能整合成一個系統對於FakeLemon比較方便."

      專案經理:"胖子,畢竟是舊功能,你還不如想一想新功能."

      胖子:"雖然資料可視化是舊功能,但我們資訊組打算對這部分進行重構,並且針對FakeLemon回傳的意見,我們將進行功能改善和優化."

      專案經理突然暴怒說:"我不是跟你說過好幾遍,公司目前沒有時間給你團隊去重構程式碼,現在程式不是能跑!! 你還不如好好想一想改善資訊組的工作效率吧!"

      胖子:"程式的確能跑,但是若此功能要整合到別的系統就有問題,而且資料可視化是經常用到的功能,因此我們應該寫成library,並且針對此library產生API文件.還有,我認為重構才會加強資訊組的工作效率,目前資訊組只有三位資深工程師,然而另兩位新人還有很多部分需要加強,因此重構一方面加強新人的能力,另一方面找出資訊組不足的部分."

      老闆:"恩....胖子你的想法是很好,但是資訊產業是講求效率,而且專案經理跟我提過資訊部門很不合群,我想重構這件事不用急於現在做,你們目前應該針對專案經理提出的缺點進行改善."

      工程師B:"老闆,我認為不只資訊要加強工作效率,我想專案經理那邊也需要.事實上,
      專案經理經常搞不清楚客戶需求,使資訊部門常常做白工.而且,之前有客戶提出我們公司常常搞不清他們的需求,我想與客戶良好交流訂出正確規格書,我想資訊部門自然而然工作效率就會高."

      聽到這些話的專案經理臉色泛紅看著工程師B.....

      胖子:"老闆,有關專案經理提出意見,我們資訊部門有做相關檢討,這次重構也是為了提升資訊部門效率才提出的.另一方面,我們資訊組認為重構不但能減少程式的bugs,而且加快程式的速度,因此也讓FakeLemon知道我們有認真維護此系統."


      老闆:"恩,專案經理也應該改善與客戶交流的部分.有關重構的部分,胖子你再跟我提出更詳細的說明,我還是不希望花太多時間在這上面."

      最後,老闆採納胖子的企劃案,但是他卻沒有感到很高興,因為工程師B沒展現真正實力,他感覺工程師B故意放水讓他贏.雖然不知為何工程師B這樣做,胖子還是很感動工程師B的幫忙,儘管老闆還是沒有接受他的重構提案,至少他爭取跟老闆詳細說明他的想法的機會.

      作者有話要說:

      這篇文主要講述各部門有堅持己見的事,然後找出最佳合作方式,而單方面退一步是無法建立健康的職場環境.或許你看上面的故事,你會覺得工程師B作為會得罪人,我只能說必須有個角色扮演得罪人的角色,一方面工程師B志向與胖子不同,另一方面工程師B只單純把這些人當作同事,因此工程師B不在乎專案經理的想法.

      事實上,我曾經很害怕與別人衝突,甚至很在乎別人的想法,因此我為了防止衝突做好此人交代的事.然而,犧牲者角色反而吃力不討好,不但出事責任由你負責扛,而且與此人衝突反而更嚴重.因此,順應別人的想法不是解決衝突最佳方案,而且一味順應只會讓自己看起來不快樂,使雙方都有滿腹不滿.其實,開會的目的就是找出各部門都能接受的方案,因此不要害怕堅持己見會傷和氣,而且職場並不是交朋友最佳場所.

      C++資料結構與演算法: 單向鏈結串列(上)

      上一篇主要解釋如何使用指標,而這篇將建立含有字串資料型態的單向鏈結串列,如圖一所示.換句話說,這次範例將實作類似Qt的QStringList,在官方文件指出QStringList繼承QList<T>,然而我使用類似QLinkedList<T>實作字串串列(a list of strings),因此實作範例將與QStringList有所不同.

      圖一.字串型態的連結串列

      下表描述QList<T>和QLinkedList<T>的差別性,基本上新增項目時(item),QLinkList是最快速的,但存取資料比較不方便.


      QList<T>
      QLinkedList<T>
      特性
      基於索引值存取(index-based access)所要的資料
      基於迭代器存取(iterator -based access)所要的資料
      利用索引值直接存取任一項目(item)
      存取任一項目(item)時,可能需要走訪所有項目
      具有陣列(Array)的特性, 因此插入或刪除資料,需要搬動其他項目
      可快速在特定位置插入資料
      存取
      易存取資料
      不易存取資料

      時間複雜度
      插入
      O(n)
      O(1)
      Prepending
      Amort. O(1)
      O(1)
      Appending
      Amort. O(1)
      O(1)

      我們先定義新的資料類型結構strNode,結構成員data為Qt的QString,而next為指向結構strNode的指標變數.typedef主要給資料型態定義新的名稱,而這裡不但將struct strNode命名為nodeptr,而且nodeptr為指向結構strNode的指標變數.

      typedef struct strNode
      {
        QString data;
        strNode *next;
      }*nodeptr;
      

      例如,我們直接使用nodeptr宣告指向結構strNode的指標變數head.

      nodeptr head;
      


      作者有話要說: 
      下一篇將利用類別來實作如何在串列後面加入(append)項目.

      C++資料結構與演算法: 計算字串長度

      int StringOperation::length(char *sptr)
      {
          char *move=sptr;
          while(*move)
          {
              move++;
          }
          return (move-sptr);
      }
      

      以上的程式碼,我利用移動指標計算字串的長度,而指標的移動主要對記憶體位置進行計算.如以下所示,我們宣告字元陣列vowel,而陣列通常在記憶體是連續的,因此指標利用此特性對字元陣列進行存取.

      char vowel[6]="AEIOU";
      

      圖一.字串陣列記憶體分布情形

      指標的移動單位與指向的資料型別有關,例如假設指標sptr指向字元資料Vowel[0],而此指標的移動單位即1 bytes,因此當程式執行sptr++時,指標所記錄的地址會從530692變成5306393. 換言之,若sptr指向浮點數資料double時,指標的移動單位則是8 bytes,因此執行sptr++時,sptr 的記憶體位置將直接加8.

      表一.變數所佔用記憶體空間
      資料型別記憶體空間
      int4 bytes
      char1 bytes
      float4 bytes
      double8 bytes
      pointer4 bytes



      Reference:

      1. Data Mapping and Storage, IBM
      2. http://publib.boulder.ibm.com/infocenter/macxhelp/v6v81/topic/com.ibm.vacpp6m.doc/proguide/ref/rvimap.htm
      3. Qt教學與開發
      4. http://chenglearning.blogspot.tw/p/qt.html

      C++資料結構與演算法: 如何反轉字串

      圖一.利用指標將字串反轉

      字串長度文章,我簡單解釋如何移動指標得到字串長度,而這篇將利用兩個指向字元資料的指標變數sptr和eptr將字串反轉.使用指標的好處計算效率比較好,它的時間複雜度為O(n).

      假設要反轉的字串為"AEIOU",sptr將指向字元陣列Vowels的起始位置,而eptr則指向Vowels的結束位置.若eptr的記憶體位址大於sptr時,eptr的字元資料將與sptr交換,而當eptr小於等於sptr將離開此迴圈.

      void StringOperation::reverse(char *sptr)
      {
          char *eptr=sptr+strlen(sptr)-1;
          while(eptr>sptr)
          {
              char temp=*sptr;
              *sptr=*eptr;
              *eptr=temp;
              ++sptr;
              --eptr;
          }
      }
      

      雖然字元所佔用記憶體空間為1 bytes, 然而指標(pointer)主要儲存記億體位址,例如一開始sptr指向Vowel[0],因此sptr將記錄Vowel[0]的記憶體位址.換句話說,在C++,儘管指標變數指向double,它所使用的記憶體空間仍然是4 bytes.


      Reference:

      1. How does this string reverse recursion work?, stackoverflow
      2. http://stackoverflow.com/questions/12663179/how-does-this-string-reverse-recursion-work
      3. Qt教學與開發
      4. http://chenglearning.blogspot.tw/p/qt.html