[問題] class template vector 設計模式。

看板C_and_CPP (C/C++)作者 (閉上眼的魚)時間14年前 (2012/06/20 22:40), 編輯推噓4(4058)
留言62則, 5人參與, 最新討論串1/1
我很努力該怎麼下標題了,不過真的想不到好的標題,見諒。 這問題應說是「請益」為佳,因手邊目前有三組 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

06/20 22:50, , 1F
囧",剛還在找推文找不到,還沒編好的緣故XD
06/20 22:50, 1F

06/21 00:19, , 2F
例3可以改成 typedef vector<TYPE> DataType;
06/21 00:19, 2F

06/21 00:19, , 3F
mData.resize(mDataCnt, DataType(mDim));
06/21 00:19, 3F

06/21 00:20, , 4F
Algor<double> aObj(DataCnt,Dim); 這樣
06/21 00:20, 4F
疑!! 有點轉不過來,這樣原本的 class DataType 就變成 template class , Algor<double> 就變成間接指定 DataType<double> 了吧 ? 那是不是代表... class DataType 會被綁死在 Algor 之上 , 假設要換另一種資料格式輸入 class newDataType 便不適用呢 ? < 抱歉有點亂 > ,先謝謝 k 大的回答與建議 :)

06/21 00:28, , 5F
話說這演算法拿來 "操作這資料結構" 還是.. "有特別要產
06/21 00:28, 5F

06/21 00:29, , 6F
生甚麼結果,而這資料結構只是設定"? @@"
06/21 00:29, 6F
舉個例子,假設是對學生「總成績」做排序,排序完後還想要知道 姓名電話、生辰八字、已婚未婚、身高體重、興趣三圍 之類的資料 (1) 科目可能會加考 C++ (2) 個資可能增加有沒有禿頭。 實質上還是對「總成績」做為演算法主軸項目,但來源的資料庫格式會不同, 所以才會先做一個 DataType, 到時要換資料庫時,就再寫另一個 NewDataType。 <當然我不是做排序啦>

06/21 01:13, , 7F
DataCnt 是執行時才會知道的, 但 Dim 都是固定的沒錯
06/21 01:13, 7F

06/21 01:14, , 8F
吧? 不會有某筆資料維度特別大的情形, 只差在你無法用
06/21 01:14, 8F

06/21 01:14, , 9F
command line args來設定而已? 用vector是為了用stl
06/21 01:14, 9F

06/21 01:14, , 10F
algorithms?
06/21 01:14, 10F

06/21 01:16, , 11F
不不不,我直說好了,是 Clustering Algorithm.
06/21 01:16, 11F

06/21 01:17, , 12F
用 vector 純粹拿來放 dataset 而已,而 DataCnt,Dim 都是
06/21 01:17, 12F

06/21 01:18, , 13F
在執行之後就固定的沒錯 (資料筆數固定才能分類)
06/21 01:18, 13F

06/21 01:19, , 14F
(換句話說,我只是看中vector高效能,而不用malloc/new)
06/21 01:19, 14F

06/21 01:31, , 15F
static array 無法?
06/21 01:31, 15F

06/21 01:34, , 16F
static array 太小了,平均測資大概是 12萬筆 * 7維/筆
06/21 01:34, 16F

06/21 01:34, , 17F
< 加上 12 萬筆資料還有二、三個屬性要紀錄 >
06/21 01:34, 17F

06/21 01:39, , 18F
Dim 的範圍是?
06/21 01:39, 18F

06/21 01:47, , 19F
5~15。同一筆資料庫 Dim 必相同 (所以固定到演算法結束)
06/21 01:47, 19F

06/21 01:55, , 20F
還有用 std::string 為必要? 所謂的必要是指上限未知
06/21 01:55, 20F
< 字串大概 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)

06/21 05:11, , 21F
06/21 05:11, 21F

06/21 15:44, , 22F
感謝指導 :)
06/21 15:44, 22F

06/21 15:59, , 23F
..........版主熬夜了
06/21 15:59, 23F

06/21 22:53, , 24F
其實我覺得用boost::multi_index就好
06/21 22:53, 24F

06/22 03:48, , 25F
我覺得問題在, 由誰去控制資料的維度, 以及如何兼顧
06/22 03:48, 25F

06/22 03:49, , 26F
資料的抽象化, 以及每一個instance的資訊的擴充性, 就
06/22 03:49, 26F

06/22 03:50, , 27F
如原po所畫, 資料可以分成兩種顏色, 所以理當是兩個不
06/22 03:50, 27F

06/22 03:51, , 28F
同型別, 但是又需要將他們關聯起來, 當然在資料型態上
06/22 03:51, 28F

06/22 03:52, , 29F
用std::vector<T>, std::string 是 overkill 了, 所以
06/22 03:52, 29F

06/22 03:54, , 30F
我才建議用static array, 考慮到空間 size_t 也太大了
06/22 03:54, 30F

06/22 04:12, , 31F
to原po: struct 裡頭包 static array 還是可以完成你
06/22 04:12, 31F

06/22 04:13, , 32F
code的功能, 還比較快
06/22 04:13, 32F

06/22 04:13, , 33F
^#2
06/22 04:13, 33F

06/22 04:25, , 34F
@k大:確實如love~大所言,速度,短期開發已不是第一目標,但
06/22 04:25, 34F

06/22 04:25, , 35F
您提供的keyword我會去找找那是幹嘛的 :)
06/22 04:25, 35F

06/22 04:28, , 36F
@loveme~大:您指的是struct包 statice array,是對 char*
06/22 04:28, 36F

06/22 04:29, , 37F
系列的變數做嗎?若有10萬筆資料(平均長度算20就好),塞
06/22 04:29, 37F

06/22 04:30, , 38F
static 應可能有危險吧 ?
06/22 04:30, 38F

06/22 04:31, , 39F
<補一下,可能我上面舉的例沒用得很好,Stu~ 和AdvStu~ 不適
06/22 04:31, 39F

06/22 04:32, , 40F
用繼承關係,可能哪天學生變動物了,但我知那怎做了,謝謝 )
06/22 04:32, 40F

06/22 04:39, , 41F
用來存你用到的features, 既然是靜態決定好的size的話
06/22 04:39, 41F

06/22 04:41, , 42F
就可, 當然也可以用 int 等可列舉的數值作為 non-type
06/22 04:41, 42F

06/22 04:41, , 43F
template arguments 來用, 所有類別皆繼承自 DataType
06/22 04:41, 43F

06/22 04:43, , 44F
<0>, 該類別 instances 用指標陣列去存, [7] 指到
06/22 04:43, 44F

06/22 04:44, , 45F
DataType<7> 提供 clone() 等方法能達成讓你動態選擇
06/22 04:44, 45F

06/22 04:47, , 46F
再來一問: 你是用interface將不同類資訊串起來嗎?
06/22 04:47, 46F

06/22 05:11, , 47F
目前只有打算一次跑一組資料庫,所以沒串起來的動作.
06/22 05:11, 47F

06/22 05:11, , 48F
也就是Stu,AdvStu一次只會跑一組.
06/22 05:11, 48F

06/22 05:21, , 49F
3Q
06/22 05:21, 49F

06/22 05:23, , 50F
簡單的話用id去表格找即可
06/22 05:23, 50F

06/22 05:24, , 51F
表格可以用一個template function來接, 符合
06/22 05:24, 51F

06/22 05:25, , 52F
Subscriptable concept 不知可不可以?
06/22 05:25, 52F

06/22 05:31, , 53F
疑!! 這真的是簡單的作法 <整個頓掉> !! 感謝 !!
06/22 05:31, 53F

06/22 13:39, , 54F
那當初的資料表要不要拆成二個呀:
06/22 13:39, 54F

06/22 13:40, , 55F
綠色: 學生; 欄位: 學號(主索引) 姓名 性別 ...
06/22 13:40, 55F

06/22 13:40, , 56F
紅色: 學生成績; 欄位: ID(主索引) 學生學號 國文 英文
06/22 13:40, 56F

06/22 13:40, , 57F
數學...
06/22 13:40, 57F

06/22 17:14, , 58F
嗯,直接拿學號當主索引沒錯。
06/22 17:14, 58F

06/22 17:24, , 59F
對了...二位大大要保重... 晚上還是睡覺比較好....
06/22 17:24, 59F

06/22 17:41, , 60F
應該也可以直接學生一個結構(就包括個資和成績)然後用指標
06/22 17:41, 60F

06/22 17:44, , 61F
比方要排序就用指標排就好 而且在回溯上也比較方便...
06/22 17:44, 61F

06/22 18:12, , 62F
那就回到我原本的 BAD CODE 3 了。
06/22 18:12, 62F
文章代碼(AID): #1FuU3O2p (C_and_CPP)
文章代碼(AID): #1FuU3O2p (C_and_CPP)