首先是昨天在北京大學oj網上看到一個簡單的算法題目,雖然簡單,但是如何完成一段高效、簡潔、讓人容易看懂的代碼對於我這個基礎不好,剛剛進入計算機行業的小白來說還是有意義的。而且在寫代碼的過程中,會發現自己平時學習中不會發現的問題,所以想寫下這個博客,主要是便於自己對算法的理解。
來,上題。
DNA Sorting Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 91599 Accepted: 36781Description
One measure of ``unsortedness'' in a sequence is the number of pairs of entries that are out of order with respect to each other. For instance, in the letter sequence ``DAABEC'', this measure is 5, since D is greater than four letters to its right and E is greater than one letter to its right. This measure is called the number of inversions in the sequence. The sequence ``AACEDGG'' has only one inversion (E and D)---it is nearly sorted---while the sequence ``ZWQM'' has 6 inversions (it is as unsorted as can be---exactly the reverse of sorted).Input
The first line contains two integers: a positive integer n (0 < n <= 50) giving the length of the strings; and a positive integer m (0 < m <= 100) giving the number of strings. These are followed by m lines, each containing a string of length n.Output
Output the list of input strings, arranged from ``most sorted'' to ``least sorted''. Since two strings can be equally sorted, then output them according to the orginal order.Sample Input
10 6 AACATGAAGG TTTTGGCCAA TTTGGCCAAA GATCAGATTT CCCGGGGGGA ATCGATGCAT
Sample Output
CCCGGGGGGA AACATGAAGG GATCAGATTT ATCGATGCAT TTTTGGCCAA TTTGGCCAAA
#01、這是一個很簡單的題目,基本上就是看完題目,思路就出來的那種。這個題目主要要解決以下幾個小麻煩。
0X001:存放DNA序列的數據結構,存放這種類型的數據,最好的當然是二維數組啦。m,n是在程序運行過程中用戶輸入的,顯然不能直接char N_DNA[n][m]來定義。
雖然題目中給出了m和n都要小於等於50,但是設一個太大的數組,還有很多空間浪費,作為一個較真的程序員,顯然是心裡過不去的。
如是,我們可以采用下面的方法定義數組,並分配空間。
1 template <typename T> 2 //定義Arr數據類型 3 class Arr 4 { 5 public: 6 Arr(int length) 7 { 8 this->length = length; 9 data = new T[length]; 10 } 11 T *data; 12 unsigned int length; 13 }; 14 typedef Arr<char>* P_of_Arr;//P_of_Arr是一維Arr數組的指針類型 15 void main() 16 { 17 int m, n; 18 scanf("%d %d", &m, &n); 19 //構造N_DNA數組 20 Arr<P_of_Arr> N_DNA(n); 21 //給N_DNA的data數組的每個指針分配空間 22 int t; 23 for (t = 0; t < n; t++) 24 { 25 N_DNA.data[t] = new Arr<char>(m); 26 } 27 }
這裡面主要用到兩個c++的知識,寫出來,加強一下自己的理解。
其一就是temptale的使用,關鍵字template在這裡的作用讓class Arr的類型多向化,就是讓class Arr可以有多種理解,就是讓class Arr成為一個模板,當在其他一些相似但是又不相同的環境下可以被再次使用。通俗點講,就是先假裝,T是已經定義的類型。讓編譯器認可它,不報錯。在Arr定義變量的時候,再來補上T的類型。因此,這樣用template模板定義的類型,可以在不同的類型T的環境中使用。
其二是new的使用,首先我們定義一個Arr數組Arr<P_of_Arr> N_DNA(n);我們可以看到Arr構造函數裡面,this->length = length;data = new T[length];將n傳給Arr域裡面的length,並且分配一個T[n]空間的數組,並把指針傳給data(注意,這裡data是二重指針,也就是數組是data[n],其中data[0,1....n]也是指針,因為定義Arr時,T是P_of_Arr,而typedef Arr<char>* P_of_Arr;//P_of_Arr是一維Arr數組的指針類型)。
int t; for (t = 0; t < n; t++) { N_DNA.data[t] = new Arr<char>(m); }
然後我們循環,依次給data[0,1...n]分配空間.每一個data[i]指向一個一維的Arr類型的數據。
至此,我們就分配了N_DNA.data[n]->data[m]的數組。
#02數據的輸入,cin的理解,cin是C++庫函數裡面的一系列函數,cin>>/cin.get/cin.getline...這些函數的用法在這裡不再贅述。
可以參考以下兩篇博客,裡面講的比較清楚
個人體會就是在使用和理解這些函數時,了解兩個方面問題。
第一、space,tab,Enter是否被從緩沖區中捨棄。<sapce,tab,Enter>
第二、cin.getline在超出范圍時,通過怎樣影響輸入標志位,來影響後續的輸入。<failbit,eofbit,badbit//goodbit>
參考博客:
http://www.cnblogs.com/A-Song/archive/2012/01/29/2331204.html
http://blog.csdn.net/dongtingzhizi/article/details/2299365
之後就是非常常規簡單的代碼了,定義一個數組rel記錄DNA的逆值,然後依次按照逆值從小到大輸出DNA序列。
完全的代碼如下:
1 #define _CRT_SECURE_NO_WARNINGS 2 #include<iostream> 3 using namespace std; 4 #define MAX 12768 5 template <typename T> 6 class Arr 7 { 8 public: 9 Arr(int length) 10 { 11 this->length = length; 12 data = new T[length]; 13 } 14 T *data; 15 unsigned int length; 16 }; 17 typedef Arr<char>* P_of_Arr; 18 int main(void) 19 { 20 int m, n; 21 scanf("%d %d", &m, &n); 22 //構造N_DNA數組 23 Arr<P_of_Arr> N_DNA(n); 24 int t; 25 for (t = 0; t < n; t++) 26 { 27 N_DNA.data[t] = new Arr<char>(m); 28 } 29 int i,j,k; 30 int *rel = new int[n]; 31 //輸入DNA序列 32 cin.getline(N_DNA.data[0]->data, m + 1); 33 for (i = 0; i < n; i++) 34 cin.getline(N_DNA.data[i]->data, m+1); 35 //循環遍歷,用rel記錄各個DNA序列的逆值 36 for (k = 0; k < n; k++) 37 { 38 rel[k] = 0; 39 for (i = 0; i < m; i++) 40 for (j = i; j < m; j++) 41 if (N_DNA.data[k]->data[i]>N_DNA.data[k]->data[j]) 42 rel[k]++; 43 } 44 int *usedrel = new int[n];//標志rel是否被用 45 //初始化全為0 46 for (i = 0; i < n; i++) 47 usedrel[i] = 0; 48 //查找最小的逆值得DNA序列,並輸出 49 for (i = 0; i < n; i++) 50 { 51 k = -1;//記錄最小逆值的地址 52 int min=MAX;//記錄最小的逆值 53 for (j = 0; j < n; j++) 54 if (rel[j] < min&&usedrel[j]==0) 55 { 56 min = rel[j]; 57 k = j; 58 } 59 usedrel[k] = 1;//標記已經被訪問 60 for (j = 0; j < m; j++) 61 cout << N_DNA.data[k]->data[j]; 62 cout << endl; 63 } 64 return 0; 65 }
運行結果如下:
由於題目對於輸入輸出有要求,所以沒有將輸入輸出分開。