2014年2月25日 星期二

初始化動態配置陣列元素值為0

#include <iostream>
using namespace std;

int main(){
    int *a = new int[5];
    int *b = new int[5]();

    int *p = a;
    int *q = a + 5;

    int *r = b;
    int *s = b + 5;

    while( p != q )
        cout << *(p++) << " ";
    cout << endl;

    while( r != s )
        cout << *(r++) << " ";
    cout << endl;

    int c[5];
    static int d[5];
    p = c;
    q = c + 5;

    r = d;
    s = d + 5;
    while( p != q )
        cout << *(p++) << " ";
    cout << endl;

    while( r != s )
        cout << *(r++) << " ";
    cout << endl;

    return 0;
}


Output:
1
2
3
4
-1819044973 -1819044973 -1819044973 -1819044973 -1819044973 
0 0 0 0 0 
-1081662640 -16121856 -1081662696 134538581 134538432 
0 0 0 0 0 


int *b = new int[5]();
只需在後面加上"( )"即可將動態配置的陣列之元素值初始為0, 另外, 因為在此scope的陣列a並非static or extern, 所以並不會自動初始化值為0 (初值為garbage)

int c[5];
static int d[5];
c之初值為garbage, d是static, 會自動初始化其元素值為0


Note:
*(p++)
等同於
*p++
因為++的優先權比*高



Array to vector

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

int main(){
    const  int size_array = 4;
    int a[size_array] = {1,2,3,4};
    int *p = a;
    int *q = a + size_array;

    int *c = p;
    while( c != q ){
        cout << *c << " ";
        c++;
    }
    cout << endl;

    vector<int> vec(p, q);
    vector<int>::iterator i = vec.begin( );
    while( i != vec.end() )
    {
        cout << *(i++) << " ";
    }
    cout << endl;

    vector<int> vec2;
    vec2.assign(p, q);
    i = vec2.begin( );
    while( i != vec2.end() )
    {
        cout << *(i++) << " ";
    }

    return 0;
}

int *q = a + size_array;
This is an off-the-end pointer

vector<int> vec(p, q);
Create a vector and use an array to initialize the elements by passing the begin pointer and off-the-end pointer

vector<int> vec2;
vec2.assign(p, q);
Create an empty vector, then using the assign function to assign the elements in an array to it
( Note: if the assign function is used, then the old contents will be wiped out, and replaced by the new contents, meanwhile, the size will be changed )



2014年2月24日 星期一

Bubble sort a singly linked list

對一個 singly linked list 做 bubble sort

Method 1 :

void LinkedList::BubbleSortVer1( ){
    if( !head ) return;
    bool change = true;
    while( change ){ //round
        Node *prev = NULL;
        Node *current = head;
        change = false;
        while( current->next != NULL ){
            if( current->value > current->next->value ){
                current = swap(current, current->next);
                change = true;
                if( prev != NULL )
                    // swap is unrelated to head, update prev' s next link
                    prev->next = current;
                else
                    // swap is related to head, change head pointer
                    head = current;
            }
            prev = current;
            current = current->next;
        }
    }
}

Node* LinkedList::swap( Node* p, Node* q){
    Node *temp = q->next;
    q->next = p;
    p->next = temp;
    return q;
}

Main idea:
  1. 藉由兩兩swap把最大的丟到最後面
  2. 利用一個change flag 來判斷sorting完成否 (可以省略計算目前是第幾round)
  3. 獨立的Swap function: 另外提出來做Node的Swap, 回傳Swap後, 前面的node, 如此可以讓iteration繼續下去
  4. 利用兩個pointer, 一個是當前指標current, 一個是current的前一個node的指標prev
  5. 比較當前node與下一個node的值, 來決定要不要swap
  6. 注意head的位置會跑掉, 必須在swap判斷時, 判斷prev的位置; 如果prev的位置是在NULL, 表示目前current是head, 必須更新head, 否則更新prev的next連結位置
  7. 前進prev和current


Method 2:

void LinkedList::BubbleSortVer2( ){
    if( !head ) return;
    bool change = true;
    Node *prevHead = new Node(0, head);
    while( change ){
        change = false;
        Node *prev = prevHead;
        Node *current = prev->next;
        while( current->next != NULL ){
            if( current->value > current->next->value ){
                prev->next = current = swap(current, current->next);
                change = true;
            }
            prev = current;
            current = current->next;
        }
    }
    head = prevHead->next;
    delete prevHead;
}

Node* LinkedList::swap( Node* p, Node* q){
    Node *temp = q->next;
    q->next = p;
    p->next = temp;
    return q;
}
Main idea:
  1. 與作法1大致相同, 只差在此方法另外開一個新的dummy node去只向head, 此時, 可以在每次swap後, 都更新前一個node的next, 不用擔心前一個是NULL
  2. 與作法1相比, 差了一個if的判斷式, 判別前一個node是不是非空, 來決定要不要更新前一個node的next, 或者是更新head


C++ code:

#include <iostream>
using namespace std;

class Node{
public:
    Node() : value(0), next(NULL) {}
    Node( int theValue, Node *theNext ) : value(theValue), next(theNext){}
    int value;
    Node *next;
};

class LinkedList{
public:
    LinkedList( );
    ~LinkedList( );
    void push_front( int value );
    void push_back( int value );
    void delete_front( );
    void show_element( );

    void BubbleSortVer1( );
    void BubbleSortVer2( );
private:
    Node* head;

    Node* swap( Node*, Node* );
};

LinkedList::LinkedList( ) : head(NULL){

}
LinkedList::~LinkedList( ){
    if( head )
        delete_front( );
}

void LinkedList::push_front( int value ){
    Node *newNode = new Node(value, head);
    head = newNode;
}

void LinkedList::push_back( int value ){
    if( !head )
        push_front( value );
    else{
        Node *current = head;
        while( current->next != NULL )
            current = current->next;
        Node *newNode = new Node(value, NULL);
        current->next = newNode;
    }
}

void LinkedList::delete_front( ){
    if( !head )
        return;
    Node *deleteNode = head;
    head = head->next;
    delete deleteNode;
}

void LinkedList::show_element( ){
    Node *current = head;
    while( current ){
        cout << current->value << " ";
        current = current->next;
    }
    cout << endl;
}

void LinkedList::BubbleSortVer1( ){
    if( !head ) return;
    bool change = true;
    while( change ){ //round
        Node *prev = NULL;
        Node *current = head;
        change = false;
        while( current->next != NULL ){
            if( current->value > current->next->value ){
                current = swap(current, current->next);
                change = true;
                if( prev != NULL )
                    // swap is unrelated to head, update prev' s next link
                    prev->next = current;
                else
                    // swap is related to head, change head pointer
                    head = current;
            }
            prev = current;
            current = current->next;
        }
        show_element( );
    }
}

void LinkedList::BubbleSortVer2( ){
    if( !head ) return;
    bool change = true;
    Node *prevHead = new Node(0, head);
    while( change ){
        change = false;
        Node *prev = prevHead;
        Node *current = prev->next;
        while( current->next != NULL ){
            if( current->value > current->next->value ){
                prev->next = current = swap(current, current->next);
                change = true;
            }
            prev = current;
            current = current->next;
        }
    }
    head = prevHead->next;
    delete prevHead;
}

Node* LinkedList::swap( Node* p, Node* q){
    Node *temp = q->next;
    q->next = p;
    p->next = temp;
    return q;
}
int main( ){
    LinkedList list;
    list.push_back( 4 );
    list.push_back( 7 );
    list.push_back( 5 );
    list.push_back( 1 );
    list.push_back( 3 );
    list.push_back( 2 );
    list.push_front( 6 );
    list.push_front( 0 );
    list.show_element( );

    list.delete_front( );
    list.show_element( );

    cout << "sorting list1: \n";
    list.BubbleSortVer2( );
    cout << "After sort: ";
    list.show_element( );

    LinkedList list2;
    list2.push_back( 1 );
    list2.push_back( 2 );
    list2.push_back( 3 );
    list2.push_back( 4 );
    list2.push_back( 5 );
    list2.push_back( 7 );
    list2.push_back( 6 );

    cout << "\nsorting list2: \n";
    list2.BubbleSortVer2( );
    cout << "After sort: ";
    list2.show_element( );
    return 0;
}

結論:
  • bubble sort將大的往後swap到底端
  • swap node另外實做一個函數, 回傳swap後前面的node, 非常重要且省事!
  • round數不需要計算node總個數, 利用change flag來觀察是否已經完成sorting
  • Maintain 兩個指標, previouscurrent, 其中previous是要用來更新swap後的鏈結方式, current是用來判斷pari間的大小關係

Reference:

Reverse a singly linked list

反轉一個單向鏈結串列
e.g.
input: 1 -> 2 -> 3 -> 4 -> 5
output: 5 -> 4 -> 3 -> 2 -> 1

Method 1:  iterative version
令一個空的head pointer叫做newHead, 將原linked list從頭掃到尾一次, 依序將掃到的結點加入newHead指向的linked list, 其中必須用一個temp pointer紀錄下一個要加入的結點, 且將原head前進

  1. temp = OldHead
  2. Advance OldHead
  3. Add temp to newHead list:     temp->next = newHead
  4. Update newHead:     newHead = temp
  5. repeat 1.~4. until OldHead pointer to NULL pointer
  6. return newHead

Method 2: Recursive version
  • Where is the sub-problem?
Input: 1 -> 2 -> 3 -> 4 -> 5 -> NULL
Sub-problem: 2 -> 3 -> 4 -> 5 -> NULL

Idea 1
1. Recursively reverse the sub-problem
2. the sub-problem part will return a pointer R points to the end of reversed linked list
3. Make R point the previous node ( need another pointer P to keep tracking the previous node)
4. return P as the recursive part's result
5. Base case: current pointer points to NULL, change the head pointer to P

缺點:
1. 需要兩個參數,一個記錄當前子問題的頭,一個紀錄前一個Node
2. head之更改必須寫死在Base case中
3. 必須回傳reverse結果的尾結點

Idea 2
1. Recursively reverse the sub-problem
2. Base case: current node's next node is NULL, change the head pointer to current node
3. current node's next' next pointer point to current node
4. current node's next point to NULL

缺點:
1. head之更改必須寫死在Base case中



C++ code:

#include <iostream>
using namespace std;

class Node{
public:
    Node( ) : value(0), next(NULL){}
    Node( int theValue, Node* nextNode ) : value(theValue), next(nextNode){}
    int value;
    Node* next;
};

class LinkedList{
public:
    LinkedList( );
    ~LinkedList( );
    void AddToEnd( int theValue );
    void AddToFront( int theValue );
    void DeleteFront( );
    void ShowElements( ) const;

    void Reverse( ); // iterative
    void RecursiveReverseComplex( ); // two parameter
    void RecursiveReverseSimple( ); // one parameter
private:
    Node* head;
    Node* recurReverseComplex( Node*, Node* ); // for RecursiveReverseComplex
    void recurReverseSimple( Node* ); // for RecursiveReverseSimple
};

LinkedList::LinkedList( ): head(NULL){ }
LinkedList::~LinkedList( ){
    while( head != NULL )
        DeleteFront();
}

void LinkedList::AddToEnd( int theValue ){
    Node *current = head;

    // empty List
    if( current == NULL ){
        AddToFront( theValue );
        return;
    }

    // Non-empty list
    while( current->next != NULL )
        current = current->next;

    Node *newNode = new Node(theValue, NULL);
    current->next = newNode;
}

void LinkedList::AddToFront( int theValue ){
    Node *newNode = new Node(theValue, head);
    head = newNode;
}

void LinkedList::DeleteFront( ){
    if( head == NULL )  return;
    Node *headNext = head->next;
    delete head;
    head = headNext;
}

void LinkedList::ShowElements( ) const{
    Node *current = head;
    while( current != NULL ){
        cout << current->value << " ";
        current = current->next;
    }
    cout << endl;
}

void LinkedList::Reverse( ){
    if( head == NULL )  return;

    Node *current = head;
    Node *newHead = NULL;
    while( current != NULL ){
        Node *temp = current;
        current = current->next;
        temp->next = newHead;
        newHead = temp;
    }
    head = newHead;
}

void LinkedList::RecursiveReverseComplex( ){
    recurReverseComplex(head, NULL);
}

Node* LinkedList::recurReverseComplex( Node* current, Node* previous){
    if( current == NULL ){
        head = previous;
        return head;
    }
    Node *reversedEnd = recurReverseComplex(current->next, current);
    reversedEnd->next = previous;
    return previous;
}

void LinkedList::RecursiveReverseSimple( ){
    recurReverseSimple( head );
}

void LinkedList::recurReverseSimple( Node* current ){
    if( current->next == NULL )
    {
        head = current;
        return;
    }
    recurReverseSimple( current->next );
    current->next->next = current;
    current->next = NULL;
}

int main( ){
    LinkedList list;
    list.AddToEnd( 2 );
    list.AddToEnd( 3 );
    list.AddToEnd( 4 );
    list.AddToEnd( 5 );
    list.AddToFront( 1 );
    list.AddToFront( 0 );
    list.ShowElements( );

    list.DeleteFront( );
    list.ShowElements( );

    list.Reverse( );
    list.ShowElements( );

    list.RecursiveReverseComplex( );
    list.ShowElements( );

    list.RecursiveReverseSimple( );
    list.ShowElements( );
    return 0;
}