2014年7月17日 星期四

STL 型式(STL idiom) vector

資料來源: http://openhome.cc/Gossip/CppGossip/vector2.html

vector的STL型式,其實就是以物件導向的方式來操作vector(如果您還沒接觸過物件導向程式設計,這邊介紹的可能稍有難度),以物件的方式來 操作vector是比較被鼓勵的方式,以下將介紹幾個vector的基本操作。

您可以建構一個元素為空的vector物件:

vector<int> ivector;

如果打算將元素放入vector中,可以使用push_back(),例如:

for(int i = 0; i < 5; i++) {
    ivector.push_back(i);
}

如果打算將元素循序取出,則可以begin()與end()方法分別傳回起始位置的iterator與結束位置的iterator,例如:

for(vector<int>::iterator it = ivector.begin();
    it != ivector.end();
    it++) {
          
    cout << *it << " ";
}
cout << endl;

iterator是標準函式庫定義類別(Class),它是一個指標,指向iterator物件的真正位址,對它進行++的動作,表示移動至 iterator的下一個元素,對它使用*運算子(Dereferences operator),表示提取出iterator目前位址的值,如果iterator走訪至結束位置的iterator的位址,表示元素走訪完畢。

雖然您可以使用下標運算子[ ]來存取vector的元素,但實際上要知道vector與陣列本質上是不相同的,當您如最上頭那樣宣告一個空的vector物件時,其容量 (capacity)為0,長度(size)也為0,所以此時您不能使用ivector[0]來取得第一個元素值,因為實際上ivector中還沒有任何 的元素。

當使用push_back()將元素加入vector時,vector的長度會自動增長,由於每次增長度都要配置記憶體過於沒有效率,所以vector會 自動先增加足夠的容量,當元素的長度超過容量時,才會再重新配置新的容量,您可以使用capacity()取得,使用size()取得元素長度,下面這個 程式綜合以上的幾個介紹作了示範:
 

#include <iostream> 
#include <vector>
using namespace std; 

int main() { 
    vector<int> ivector;
 
    for(int i = 0; i < 10; i++) {
        ivector.push_back(i);
    }
 
    for(vector<int>::iterator it = ivector.begin();
        it != ivector.end();
        it++) {
 
        cout << *it << " ";
    }
    cout << endl;
 
    cout << "capacity: " << ivector.capacity() << endl
         << "size: " << ivector.size() << endl;
 
    return 0; 
}

結果如下:
0 1 2 3 4 5 6 7 8 9
capacity: 16
size: 10

如果打算對vector進行排序、尋找、反轉等操作,可以使用標準函式庫中的泛型演算法,要使用泛型演算法必須先含入表頭檔:
#include <algorithm>

下面這個程式直接示範了排序、尋找、反轉等操作:


#include <algorithm>
#include <iostream> 
#include <vector>
using namespace std; 

int main() { 
    int iarr[] = {30, 12, 55, 31, 98, 11, 41, 80, 66, 21};
    vector<int> ivector(iarr, iarr + 10);
 
    // 排序 
    sort(ivector.begin(), ivector.end());
 
    for(vector<int>::iterator it = ivector.begin();
        it != ivector.end();
        it++) {
 
    cout << *it << " ";
    }
    cout << endl;

    cout << "輸入搜尋值:";
    int search = 0;
    cin >> search;
 
    vector<int>::iterator it = 
    find(ivector.begin(), ivector.end(), search);
 
    if(it != ivector.end()) {
        cout << "找到搜尋值!" << endl;
    }
    else {
        cout << "找不到搜尋值!" << endl;
    }
 
    // 反轉 
    reverse(ivector.begin(), ivector.end());
 
    for(vector<int>::iterator it = ivector.begin();
        it != ivector.end();
        it++) {
 
        cout << *it << " ";
    }
    cout << endl;
 
    return 0; 
}

執行結果:
11 12 21 30 31 41 55 66 80 98
輸入搜尋值:41
找到搜尋值!
98 80 66 55 41 31 30 21 12 11

陣列型式(Array idiom) vector

資料來源:http://openhome.cc/Gossip/CppGossip/vector1.html


您可以使用vector來替代陣列,並使用陣列型式(Array idiom)的方式來操作vector,要使用vector,必須含入vector表頭檔:
#include <vector>

要建立vector型態的物件(Object),您必須提供元素型態與長度資訊,例如下例中建立int元素的vector,並擁有10個元素:

vector<int> ivector(10);

您可以模彷陣列中存取元素的方式來存取vector的元素,使用下標(Subscript)運算子並指定索引來取得指定的元素,例如:


#include <iostream> 
#include <vector>
using namespace std; 

int main() { 
    vector<int> ivector(10);
 
    for(int i = 0; i < ivector.size(); i++) {
        ivector[i] = i;
    }
 
    for(int i = 0; i < ivector.size(); i++) {
        cout << ivector[i] << " ";
    }
    cout << endl;

    return 0; 
}

執行結果: 

0 1 2 3 4 5 6 7 8 9

與陣列型態不同的是,vector記得自己的長度資訊,您可以使用size()查詢vector的元素長度,或是使用empty()測試長度是否為0。

當您宣告vector物件時,所有的元素值會有與型態相應的初始值,例如算術相關型態會被初始為0,指標型態初始為0(表示不指向任何位址),如果您打算 將所有元素初始為指定的值,則可以如下:

vector<int> ivector(10, 5);

上例中將宣告有10個元素的vector,並將所有的元素值初始為5。

如果您願意,您可以使用一個陣列來作為建構vector的引數(Argument),如此建構出來的vector會擁有陣列所指定的元素初值,在這之前, 您要先知道,宣告一個陣列時,陣列名稱所儲存的是第一個元素在記憶體中的位址值,對該位址值加一,表示移至下一個元素,當使用陣列來建構vector時, 要指定的是元素的起始位址與最後一個元素的下一個位址,例如以整個陣列來建構vector的話,可以這麼撰寫:

#include <iostream> 
#include <vector>
using namespace std; 

int main() { 
    int iarr[] = {1, 2, 3, 4, 5};
 
    vector<int> ivector(iarr, iarr + 5);
 
    for(int i = 0; i < ivector.size(); i++) {
        cout << ivector[i] << " ";
    }
    cout << endl;
 
    return 0; 
}

執行結果: 

1 2 3 4 5

如果打算只使用陣列中的某個範圍來建構vector,例如複製索引1到3的元素,則可以如下:

#include <iostream> 
#include <vector>
using namespace std; 

int main() { 
    int iarr[] = {1, 2, 3, 4, 5};
 
    vector<int> ivector(iarr + 1, iarr + 4);
 
    for(int i = 0; i < ivector.size(); i++) {
        cout << ivector[i] << " ";
    }
    cout << endl;

    return 0; 
}

執行結果: 

2 3 4

vector可以使用另一個vector作為引數來建構,例如以ivector1作為引數來建構ivector2:
vector<int> ivector1(5, 1);
vector<int> ivector2(ivector1);

vector可以使用=直接指定給另一個vector,這會將vector的值複製給被指定的vector,例如:


#include <iostream> 
#include <vector>
using namespace std; 

int main() { 
    vector<int> ivector1(5, 1);
    vector<int> ivector2; // 定義一個空的vector
 
    ivector2 = ivector1;
 
    for(int i = 0; i < ivector2.size(); i++) {
        cout << ivector2[i] << " ";
    }
    cout << endl;
 
    ivector2[0] = 2;

    for(int i = 0; i < ivector2.size(); i++) {
        cout << ivector2[i] << " ";
    }
    cout << endl;
 
    for(int i = 0; i < ivector1.size(); i++) {
        cout << ivector1[i] << " ";
    }
    cout << endl;
 
    return 0; 
}

由於指定時是將值一一複製加入目標vector,所以您改變目標vector的值,並不會影響原來的vector, 執行結果如下: 

1 1 1 1 1
2 1 1 1 1
1 1 1 1 1

陣列

1.
宣告陣列之後,陣列所配置到的記憶體空間中所儲存的數是未知的,所以在初始陣列元素值之前,當中的元素值是未知的,如果您在宣告變數時尚未決定陣列中的 值,可以這麼宣告陣列: 
    int irr[10] = {0}; 
    double darr[10] = {0.0}; 
    char carr[10] = {'\0'};

    bool barr[10] = {false};

2.
如果您在宣告陣列時只希望初始幾個元素,則可以這麼宣告: 
int iarr[5] = {0, 1}; 
double darr[5] = {0.0, 0.1}; 
char carr[5] = {'A', 'B'}; 
bool barr[5] = {false, true};

像上例中,都只初始索引0與索引1的兩個元素,其它未初始的元素,整數的話會自動初始為0,浮點數的話會自動初始為0.0,字元的話會自動初始為空字元 ('\0'),而boolean數的話會自動初始為false。 


3.
如何得知陣列的長度:
    int iarr[] = {1, 2, 3, 4, 5, 6};
  陣列長度為: sizeof(iarr) / sizeof(iarr[0])


4.
不可以將陣列直接指定給另一個陣列,或是直接比較兩個陣列是否相同
int arr1[5];
int arr2[5];
...
arr1 = arr2; // 錯誤!不能直接指定陣列給另一個陣列
...
if(arr1 == arr2) { // 錯誤!不能直接比較兩個陣列是否相同
    ...
}

只能循序一個一個元素進行複製或比對


Java整理

1. >>> : shift right並且強迫補0
   >>是根據signed bit去補


2014年7月15日 星期二

decodeFile/decodeStream的問題

decodeFile( )/decodeStream( )可能會有OutOfMemory exception的問題
所以改用decodeFileDescriptor( )會比較好
它呼叫與decodeFile( )/decodeStream( )不同的native function
其Bitmap不是用標準的Java方式去allocate的  應該是在virtual heap外另外allocate

參考資料:
http://www.cnblogs.com/akira90/archive/2013/03/15/2960666.html