看板 C_and_CPP 關於我們 聯絡資訊
我很努力該怎麼下標題了,不過真的想不到好的標題,見諒。 這問題應說是「請益」為佳,因手邊目前有三組 solution,覺得都不夠好。 問 題 敘 述 我有一組演算法,裡面主要的資料結構是一個二維陣列,外帶資料一些屬性值, 一開始沒想太多,程式碼直觀寫,大致如下。 B.A.D. C O D E - 1 class Algor{ private: vector< vector<double> > mSrcData; vector< string > mName; vecotr< size_t > mId; size_t mDataCnt; size_t mDim; public: Algor(size_t DataCnt, size_t Dim) { mDataCnt = DataCnt, mDim = Dim; mSrcData.resize( mDataCnt, vector<mDim>() ); } }; 後來認為這樣設計很糟,速度是最快的沒錯,但因為測試資料屬性可能常變動, 所以決定把 Data 封裝起來。 B.A.D. C O D E - 2 Data 重封裝的話 vector 就要打散,在個別的 class 裡, 但我又想要保留記憶體配置快的優點,於是想到在 DataType 那裡加個 template, 引數為 size, Code 大致長這樣。 template<size_t dtDim> class DataType{ private: vector<double> dtData; string dtName; size_t dtId; public: DataType(){dtData.resize(dtDim);} DataType(const string & Name, const size_t & Id){ dtName = Name, dtId = Id; dtData.resize(dtDim); } }; template<typename TYPE> class Algor{ private: vector< TYPE > mData; size_t mDataCnt; public: Algor(const size_t & DataCnt) { mDataCnt = DataCnt; mData.resize( mDataCnt, TYPE() ); } }; 到時候在呼叫端的時候變這樣 Algor< DataType<Dim> > aObj(DataCnt); 又有一個問題出現了,這種設計模式必須在編譯期時確定 Dim , 但我想讓這種程式在 console 下用 argc / argv 讀設定檔也可以跑, 所以這個又被告吹了。 B.A.D. C O D E - 3 最後只好叫電腦幫我做苦工,把 DataType 那裡的 template 拿掉, 到最後在讀檔案時只好這麼做.. class DataType{ private: vector<double> dtData; size_t dtDim; /* 其餘略 */ public: DataType(const size_t & Dim) : dtDim(Dim){ dtData.resize(dtDim); } }; template<typename TYPE> class Algor{ private: vector< TYPE > mData; size_t mDataCnt, mDim; public: Algor(const size_t & DataCnt , const size_t & Dim) { mDataCnt = DataCnt, mDim = Dim; mData.resize( mDataCnt, TYPE(mDim) ); } }; 在呼叫端使用時就變成了 Algor< DataType > aObj(DataCnt,Dim); 想請教,這種設計模式是正常的嗎? < 我寫到現在一直還覺得有點怪怪的 > 謝謝各位先進的意見與不吝指教。< 還沒編好便不小心送出,先說聲抱歉 > -- 「自從我學了 C# , 人都變聰明 , 考試都考一百分」 「自從我學了 VB , 皮膚都變好 , 人也變漂亮了 」 「自從我學了 Java , 明顯變壯 , 個子也變高了 」 「自從我學了 C++ , 內分泌失調 , 頭都禿了... 」 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 180.177.76.161
s3748679:囧",剛還在找推文找不到,還沒編好的緣故XD 06/20 22:50
kevingwn:例3可以改成 typedef vector<TYPE> DataType; 06/21 00:19
kevingwn:mData.resize(mDataCnt, DataType(mDim)); 06/21 00:19
kevingwn:Algor<double> aObj(DataCnt,Dim); 這樣 06/21 00:20
疑!! 有點轉不過來,這樣原本的 class DataType 就變成 template class , Algor<double> 就變成間接指定 DataType<double> 了吧 ? 那是不是代表... class DataType 會被綁死在 Algor 之上 , 假設要換另一種資料格式輸入 class newDataType 便不適用呢 ? < 抱歉有點亂 > ,先謝謝 k 大的回答與建議 :)
s3748679:話說這演算法拿來 "操作這資料結構" 還是.. "有特別要產 06/21 00:28
s3748679:生甚麼結果,而這資料結構只是設定"? @@" 06/21 00:29
舉個例子,假設是對學生「總成績」做排序,排序完後還想要知道 姓名電話、生辰八字、已婚未婚、身高體重、興趣三圍 之類的資料 (1) 科目可能會加考 C++ (2) 個資可能增加有沒有禿頭。 實質上還是對「總成績」做為演算法主軸項目,但來源的資料庫格式會不同, 所以才會先做一個 DataType, 到時要換資料庫時,就再寫另一個 NewDataType。 <當然我不是做排序啦>
loveme00835:DataCnt 是執行時才會知道的, 但 Dim 都是固定的沒錯 06/21 01:13
loveme00835:吧? 不會有某筆資料維度特別大的情形, 只差在你無法用 06/21 01:14
loveme00835:command line args來設定而已? 用vector是為了用stl 06/21 01:14
loveme00835:algorithms? 06/21 01:14
EdisonX:不不不,我直說好了,是 Clustering Algorithm. 06/21 01:16
EdisonX:用 vector 純粹拿來放 dataset 而已,而 DataCnt,Dim 都是 06/21 01:17
EdisonX:在執行之後就固定的沒錯 (資料筆數固定才能分類) 06/21 01:18
EdisonX:(換句話說,我只是看中vector高效能,而不用malloc/new) 06/21 01:19
loveme00835:static array 無法? 06/21 01:31
EdisonX:static array 太小了,平均測資大概是 12萬筆 * 7維/筆 06/21 01:34
EdisonX:< 加上 12 萬筆資料還有二、三個屬性要紀錄 > 06/21 01:34
loveme00835:Dim 的範圍是? 06/21 01:39
EdisonX:5~15。同一筆資料庫 Dim 必相同 (所以固定到演算法結束) 06/21 01:47
loveme00835:還有用 std::string 為必要? 所謂的必要是指上限未知 06/21 01:55
< 字串大概 30~50 ascii 字左右 > 我舉個例子好了,假設現在 資料庫1 長這樣 姓名 學號 國文 英文 數學 真正在做演算法的只有這三筆,所以 DIM = 3; 但在做完演算法的時候,我還要回查姓名跟學號,所以多了 string 、 id, 以純 array 來表示,大概長這樣。 string name[DATA_CNT]; // 這是到時候要回溯的資料,不參與演算過程 size_t ID[DATA_CNT]; // 這也是到時要回溯的資料,也不參與演算過程 double Data[DATA_CNT][DIM=3]; // 有三科成積,但這裡就不分國英數了 如果最後我排完了名次,最後我還希望「第一名是誰」、「第二名是誰」, 沒有 string、 ID 的話,我只能知道第一名是幾分,沒辦法知道他是誰吧。 然而今天資料庫屬性如果換過的話 姓名 學號 姓別 學校 國文 英文 數學 C++ 健康教育 這時 DIM 就變 5 ,而其它在排完名次後的資料全部都還要繼續回溯的話 string name[DATA_CNT2]; size_t ID[DATA_CNT2]; char sex[DATA_CNT2]; string school[DATA_CNT2]; double Data[DATA_CNT2][DIM=5]; // 變五科成積了 但本質上,要做的事情都是對 Data 做分析,只是做完分析後要回溯的東西不一樣 所以後來才會想說開一個 Algro<DataType> , 若對於欄位需求有所不同時, 其他 coder 應該只要寫一份自己的 class DataType 即可 <當然這是小弟愚見> 故才在想說,這份設計架構是否合理? < 說聲抱歉,這問題被我說得 零零落落 ,我盡可能讓它清楚了> 在此先謝謝 loveme00835 願意看我這麼長敘述的問題。 :) ※ 編輯: EdisonX 來自: 180.177.76.161 (06/21 02:16)
loveme00835:http://ideone.com/T2tdn 06/21 05:11
EdisonX:感謝指導 :) 06/21 15:44
s3748679:..........版主熬夜了 06/21 15:59
kevingwn:其實我覺得用boost::multi_index就好 06/21 22:53
loveme00835:我覺得問題在, 由誰去控制資料的維度, 以及如何兼顧 06/22 03:48
loveme00835:資料的抽象化, 以及每一個instance的資訊的擴充性, 就 06/22 03:49
loveme00835:如原po所畫, 資料可以分成兩種顏色, 所以理當是兩個不 06/22 03:50
loveme00835:同型別, 但是又需要將他們關聯起來, 當然在資料型態上 06/22 03:51
loveme00835:用std::vector<T>, std::string 是 overkill 了, 所以 06/22 03:52
loveme00835:我才建議用static array, 考慮到空間 size_t 也太大了 06/22 03:54
loveme00835:to原po: struct 裡頭包 static array 還是可以完成你 06/22 04:12
loveme00835:code的功能, 還比較快 06/22 04:13
loveme00835: ^#2 06/22 04:13
EdisonX:@k大:確實如love~大所言,速度,短期開發已不是第一目標,但 06/22 04:25
EdisonX:您提供的keyword我會去找找那是幹嘛的 :) 06/22 04:25
EdisonX:@loveme~大:您指的是struct包 statice array,是對 char* 06/22 04:28
EdisonX:系列的變數做嗎?若有10萬筆資料(平均長度算20就好),塞 06/22 04:29
EdisonX:static 應可能有危險吧 ? 06/22 04:30
EdisonX:<補一下,可能我上面舉的例沒用得很好,Stu~ 和AdvStu~ 不適 06/22 04:31
EdisonX:用繼承關係,可能哪天學生變動物了,但我知那怎做了,謝謝 ) 06/22 04:32
loveme00835:用來存你用到的features, 既然是靜態決定好的size的話 06/22 04:39
loveme00835:就可, 當然也可以用 int 等可列舉的數值作為 non-type 06/22 04:41
loveme00835:template arguments 來用, 所有類別皆繼承自 DataType 06/22 04:41
loveme00835:<0>, 該類別 instances 用指標陣列去存, [7] 指到 06/22 04:43
loveme00835:DataType<7> 提供 clone() 等方法能達成讓你動態選擇 06/22 04:44
loveme00835:再來一問: 你是用interface將不同類資訊串起來嗎? 06/22 04:47
EdisonX:目前只有打算一次跑一組資料庫,所以沒串起來的動作. 06/22 05:11
EdisonX:也就是Stu,AdvStu一次只會跑一組. 06/22 05:11
loveme00835:3Q 06/22 05:21
loveme00835:簡單的話用id去表格找即可 06/22 05:23
loveme00835:表格可以用一個template function來接, 符合 06/22 05:24
loveme00835:Subscriptable concept 不知可不可以? 06/22 05:25
EdisonX:疑!! 這真的是簡單的作法 <整個頓掉> !! 感謝 !! 06/22 05:31
s3748679:那當初的資料表要不要拆成二個呀: 06/22 13:39
s3748679:綠色: 學生; 欄位: 學號(主索引) 姓名 性別 ... 06/22 13:40
s3748679:紅色: 學生成績; 欄位: ID(主索引) 學生學號 國文 英文 06/22 13:40
s3748679: 數學... 06/22 13:40
EdisonX:嗯,直接拿學號當主索引沒錯。 06/22 17:14
s3748679:對了...二位大大要保重... 晚上還是睡覺比較好.... 06/22 17:24
firejox:應該也可以直接學生一個結構(就包括個資和成績)然後用指標 06/22 17:41
firejox:比方要排序就用指標排就好 而且在回溯上也比較方便... 06/22 17:44
EdisonX:那就回到我原本的 BAD CODE 3 了。 06/22 18:12