【C++】使用struct array和一維int array模擬二維int array

URL Link //n.sfs.tw/14884

2020-12-25 22:40:01 By 過路君子

大家好,這裡是今天只想耍廢一整天的小編過路君子

回到了圖像世界真美妙,純文字世界到底是什麼鬼,根本不是給人用的

 

會研究這個小編主要有兩個原因:第一、懶得去研究怎麼用sort排序二維陣列;第二、希望能只讀一次檔案就把所有資料處理完畢或是先整理再來慢慢料理。

這有「略微」的牽涉到指標,然後小編是用很偷懶的方式要記憶體,其實真的要寫應該要用new來要,以後再來考慮要不要完善這個非常非常陽春的程式碼。

先備知識:

1、struct和struct陣列在程式中的表達方式

2、函式function(副程式)

3、#include<fstream>使用方法

4、#define的用法,例如:#define add2(x) (x)+2之類的

5、指標(*)

6、這個程式檔是用來求總合(會溢位)、平均和中位數

因為上述那堆在網路上已經有一堆教學文章,然後小編這篇文章重點也不在這堆東西上,所以接下來小編會當各位上方都非常熟悉的前提來講解,要不然光指標小編就可以寫個五篇多的文章來介紹,根本講不完……

對了,小編實際處理的檔案是有20種資料然後數百行,全部貼出估計沒人要看,下面的示意圖就用5*4筆資料來做個示意就好~~

那就先上全程式碼,下面小編再來解釋:

※然後這是示範輸入資料,僅作示範,絕對會跟上方程式所處理的資料有落差,但概念一樣。

時間 參數1 參數2 參數3

491876 124110 105 2153
506417 126797 370 3499
530118 146530 92 3495
520414 133360 92 3204
536545 133814 55 3070

(以下僅節錄重點講解)

前五行

#include<algorithm>
#include<iostream>
#include<fstream>
#define UNI 19		//Type of data
#define MAX 5000	//Data quantity

基本定義,第一個是sort的定義籤頭檔;第二個是c++的標準籤頭檔;第三個則跟檔案的讀寫有關。

第四、第五行只是定義兩個變數而已,這樣以後要改動資料就只要改兩個地方就好,不用在程式裡慢慢的一個一個改,太白癡了。

 

第九到第十二行

struct ac
{
	int val[MAX];
}ss[UNI];

這次用來儲存每種資料的核心,因為要找出中位數,所以不能用新的資料覆蓋舊的資料,必須全部保存起來,進行排序。

在這裡小編創建了19個struct array,每個struct裡面有一個int array,而每個int array裡面有5000個int。

為什麼不是20個呢?因為每列的第一行是時間戳記(timestamp)不用處理^ ^

 

第十八到第二十行

int none, date[UNI], tol[UNI]={0}, much=0;
ifstream ux;
ofstream ui;

指定四個int型態的變數:none用來判斷是否還有時間戳記;date用來暫存從文件讀進來的資料,共19個;tol用來加總每一種資料,也是十九種資料各個的總和。

接下來指定兩種變數,ux是表示這個檔案呈現讀取狀態(不寫入資料),ui則是表示這個檔案呈現寫入狀態(不讀取其內資料);順帶一提,若要同時讀取和寫入檔案則是使用fstream搭配ios進行設定(ios::in和ios::out)。

 

第二十五到三十四行

while(ux>>none)
{
	for(int ky=0;UNI>ky;ky++)
	{
		ux >> date[ky];
		(ss+ky) -> val[much] = date[ky];
		tol[ky] += date[ky];
	}
	much++;
}

while迴圈的判斷條件其實也是小編滿喜歡使用的方式,因為每行固定20筆資料且第一筆資料我們不要,所以用此方式來判斷還有沒有資料,當然用feof也可以,就看個人喜好了。

接下來的for迴圈就是讀取資料的核心了,如果有心,三行可以併成兩行,但計算加總的功能小編先寫完才加上計算中位數的功能,當下寫怕邏輯崩壞所以分開寫,雖說中間還是歷經了三次邏輯崩壞......

可能直接讀程式碼會有點抽象,下面放出目前資料儲存狀況:

參數1(位於struct[0]的int array內) > 124110 126797 146530 133360 133814

參數2(位於struct[1]的int array內) > 105 370 92 92 55

參數3(位於struct[2]的int array內) > 2153 3499 3495 3204 3070

沒錯,時間戳記被小編拋棄了,因為我們不需要,而經過這個迴圈之後,原本我們的資料是一列有三種資料(不含時間戳記)共五行,現在就被整理成了一列只有一種資料共三行(同種類的放一起),直行橫列。

 

第四十五行+第七十四到七十七行

for(int ro=0;UNI>ro;ro++) sort((ss+ro)->val, ((ss+ro)->val)+much, compare);
bool compare(int a, int b) 
{
	return a > b;
}

這行簡單來說就是將剛剛我們分離出來的資料按照從大到小排序(降序),如果各位要資料按照從小到大排序(升序),就只要把return a>b;改成return a<b;就可以了。

關於sort的用法...小編就先丟定義出來:sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp);簡單來說,有三個參數要帶進sort裡面:第一個參數要放陣列起始位置、第二個參數要放陣列結束位置和第三個參數則是放排序的方式(要自己寫函式function放進去)。

那這裡小編一樣放上目前資料狀況,這樣比小編在上面打一堆字還有用:

ss -> val  =>  146530 133814 133360 126797 124110

(ss + 1) -> val  =>  370 105 92 92 55

(ss + 2) -> val  =>  3499 3495 3204 3070 2153

小編就直接簡化表示了,真的不懂意思就往回看吧,跟上面那一大串國字是同樣意思。

從上方就很明顯了吧,經過這一行,資料就已經整理完了!

 

接下來的程式碼就是去抓取中位數而已,想必如果各位上方那堆都看得懂的話,那單純的取值出來應該不會太難吧。

話說,光是從struct陣列裡面取指定的值出來就有四種寫法,目前小編也只記了兩種,也就是目前各位在上方看到的用'->'的寫法,另一種則是用'.'的寫法,剩下沒記。

再說一遍,這個程式碼小編寫的超級陽春,有很多問題都被小編先丟一旁,簡單舉幾個問題:一、資料超過21億就會溢位;二、增減資料種類個數都得動到程式碼,程式碼本身無法自動捕捉有幾種資料;三、這個程式碼只針對某個檔案,如果今天有複數的檔案要做同樣的事情,恐怕也得動到程式碼......諸如此類的問題待解決,還是個非常陽春的程式碼。

 

 

 

後記:

這樣詳細的整理下來,小編發現結果反而非核心程式的部分寫的比較長,到底是發生了什麼事情呢?

總之能刻出這個程式小編也很驚訝,基本上目前小編所有學過的東西都在裡面了,要再更花俏的技巧沒了,簡直根本就是一個大驗收,寫了很久、很痛苦,但寫完就一個字:超級開心!

這次也是初次挑戰用struct搭配int array來模擬int的二維陣列,結果竟然可行,實則也嚇到了小編自己,感覺後記有點太興奮了,就到這裡吧,挑戰~成功三分之一!