顯示具有 Data Struct 標籤的文章。 顯示所有文章
顯示具有 Data Struct 標籤的文章。 顯示所有文章

2013年2月1日

Non-Recursive Binary Search tree implement in C++

Tree

Def:  A finite set constituted by one or more nodes 

     1. The tree has a specific node which is called Root
     
        2. The other nodes is n (n>=0) mutually exclusive collection of T1、T2.......Tn.
            These collections are a tree. It is called the subtree of the root.


The tree is shown in figure below:

fig.1

If we use linked list to implement tree. One node is like this:
fig.2
This waste too much space to storage the link,even we didn't use them.


Binary Tree

def: A finite set constructed by nodes.   Binary Tree can be empty or it is constructed by the root , the left subtree , right subtree. The left subtree and right subtree are also binary tree .

What different between tree and binary tree?

1. Tree can be empty,but binary tree can not.

2. Tree degree is > = zero but binary tree degree is between zero to two.

3. Subtree of the tree have no order .   Subtree of the binary tree have order .

Special Binary Tree

Skewed Binary Tree:
1. left skewed binary tree
fig.3
Tree node only have left child.

2. right skewed binary tree
fig.4


Tree node only have right child.

Full Binary Tree:
def: If a full binary tree has a depth called k. Then a full binary tree have ((2^k)-1) number of node
fig.5

Complete Binary Tree:
def: If a complete binary tree tree has a depth called k.
       1. number of node < = (2^k)-1

property: 1. The number of left child is 2 * i , if (2 * i) > node , then it have no left child.

              2. The number of right child is (2 * i)+1 ,  if (2 * i) +1> node , then it have no right child.

              3. The number of parent node is floor( i / 2 ) , if  floor( i / 2 ) < 1 , then it have no
                    parent node.


fig.6

Binary tree data structure

Using linked list:
fig.7

if Binary Tree have n number of node.  The link space is 2n.(totle)

And we really use n-1 space by link, so we waste 2n-(n-1)=n+1 (link space)

Advantage:
It is convenient for delete node and insert node.

Drawback:
It waste  a half of space.
Every node can not find parent node.


Using array:
Change a binary tree to a full binary tree , and the node number will map to  array.

Giving the depth of tree is k, the array size will be (2^k)-1.

For the case shown in fig. 7 , the mapping of the array:
fig.8
Advantage:
It is easy to find parent node and child.
It is no necessary to store link.

Drawback:
It is not easy to delete and insert a node.
If the tree is a Skewed Binary Tree , then that is waste too much array space.

Binary Tree Traversal

def: Visit all node in a tree.


fig.9


1. Preorder : DLR
2. Inorder : LDR
3. Postorder : LRD


For the case shown in figure 10, we will have a binary tree is shown in below:



                                                                          fig.10

The preorder is "ABDC"
The inorder is "DBAC"
The postorder is "DBCA"

Binary Search Tree

def: If binary search is not empty !
       1.The key value of left subtree is less than  key value of root.
       2.The key value of right subtree is greater than key value of root.
       3.Right subtree and left subtree are also binary search tree.

So a binary search is like this :
fig.11

Sort of Binary Search Tree

Using inorder if you want sort a binary search tree.

For this case , the result of inorder is " 2 5 6 7 9 14 " .


Search of Binary Search Tree

It is a binary search tree want search a key value called k.
1. If key value of root is equal k , then we found it!
2. If key value of root is less than k , then we go to the left subtree of root.
3. If key value of root is greater than k , then we go to the right subtree of root.

The average number of comparisons for a binary search tree is big-o ( n )
The optimal number of comparisons for a binary search tree is big-o ( log n )

Delete of Binary Search Tree

1.If the node that we want delete is a leaf , then just delete it and let the link of parent be null.
2.If the node that we want delete is not a leaf but it only have one child.
   Then link the parent node and child node together.
3.If the node that we want delete have two child , then find the greatest key value of left subtree
   or find the least key value of right subtree and then replace it.





Non-Recursive Binary Search tree implement in C++

///BST.h///


#ifndef BST_H
#define BST_H
#include <iostream>

class BST{
private:
    int Node_Number;
    int Top;
    int PopCount;
    int DeleteData;
    struct TreeNode *STACK;
    struct TreeNode *root;
    struct TreeNode *ptr;
    struct TreeNode *current;
    struct TreeNode *pre;
    struct TreeNode *clear;
public:
    BST();
    ~BST();
    void Add();
    void Sort();
    void Delete();
    TreeNode* FindFather(int num);
    TreeNode* SearchNumber(int num);
    void Search();
    void inorder(TreeNode *D);
    void push(TreeNode *temp);
    void pop();
    void ClearMemory(TreeNode *D);
};

#endif


///BST.cpp///

#include "BST.h"

using namespace std;
struct TreeNode{
    int IntData;
    struct TreeNode *Llink;
    struct TreeNode *Rlink;
};

BST::BST(){    
    root=NULL;
    Node_Number=0;
    Top=-1;
    PopCount=0;
}

BST::~BST(){
    current=root;
    ClearMemory(current);
    cout<<"The memory is released"<<endl;
    system("Pause");
}

void BST::Add(){
    Node_Number++;
    ptr=new TreeNode;
    ptr->Llink=NULL;
    ptr->Rlink=NULL;
    cout<<"Please Enter the Integer"<<endl;
    cin>>ptr->IntData;
    if(root==NULL){        //For now the tree is still empty so the new node will be root!
        root=ptr;
    }else{    //The tree is not empty!
            if(SearchNumber(ptr->IntData)!=NULL){        //Binary Search tree can not have the same data!
                cout<<"Error! You have the same Integer!!"<<endl;
                return;        //Jump to the menu!
            }
            current=root;    
            while(current!=NULL){    
                if(ptr->IntData<current->IntData){    //Compare two integer. If node of ptr is less than node of currnet then put 
                                                    //the node of ptr to left subtree.
                    if(current->Llink==NULL){    //Consider the node is a leaf!
                        current->Llink=ptr;
                        ptr->Llink=NULL;
                        ptr->Rlink=NULL;
                        current=NULL;
                    }else{
                        current=current->Llink;  //Move to the next left child
                    }
                }else{    //If node of ptr is bigger than node of currnet then put the node of ptr to right subtree.
                    if(current->Rlink==NULL){    //Consider the node is a leaf!
                        current->Rlink=ptr;
                        ptr->Llink=NULL;
                        ptr->Rlink=NULL;
                        current=NULL;
                    }else{
                        current=current->Rlink;  //Move to the next right child
                    }
                }
            
        }
    }
}

void BST::Delete(){
    if(root==NULL){    
        cout<<"The tree is empty!"<<endl;
    }else{
        Sort();        //show integer
    }
    cout<<"Which one do you want delete? :"<<endl;
    cin>>DeleteData;
    if(SearchNumber(DeleteData)==NULL){
        cout<<"Error!! Can not find this Integer!!"<<endl;
        return;
    }else{
        current=SearchNumber(DeleteData);        //Find the integer
    }
    TreeNode *temp;
    if(current==root&&Node_Number==1){    //Consider the delete integer is root node and it is only one node in tree!
        clear=current;
        root=NULL;
        delete clear;
        Node_Number--;
        return;
    }else if(current==root){    //Consider the delete integer is root node and it is not only one node in tree!
        if(root->Llink==NULL){    //Consider it is no left subtree!
            clear=root;
            root=root->Rlink;
            delete clear;
            Node_Number--;
            return;
        }else if(root->Rlink==NULL){    //Consider it is no right subtree!
            clear=root;
            root=root->Llink;
            delete clear;
            Node_Number--;
            return;
        }else{    //If the root have left subtree and right subtree!
            temp=current;
            temp=temp->Llink;    //Move to the left child! Beacuse I want to choose the biggest node of left subtree to replace the node of root! 
            if(temp->Rlink==NULL){    //In the left subtree. The biggest node always at right node! Now Consider if the left subtree have no right node!
                temp->Rlink=root->Rlink;    
                clear=root;
                root=temp;
                delete clear;
                Node_Number--;
                return;
            }else{
                while(temp->Rlink!=NULL){    //Last right node is the bigest node in left subtree of root!
                    temp=temp->Rlink;        //Keep move to the right node!
                }    
                pre=FindFather(temp->IntData);    //Find this node's parent
                if(temp->Llink==NULL){    //Consider two case. if temp node have no leftchild then his parent doesn't need to link any node!
                    pre->Rlink=NULL;        
                }else{
                    pre->Rlink=temp->Llink;    //The other case is if temp node have leftchild then his parent need to link leftchild!
                }
                temp->Llink=root->Llink;    //Replace the delete node!
                temp->Rlink=root->Rlink;
                clear=root;
                root=temp;
                delete clear;    //Delete
                Node_Number--;
                return;
            }
        }
    }    
    
    if(current->Llink==NULL&&current->Rlink==NULL){        //if the node we want to delete is a leaf 
        pre=FindFather(current->IntData);    //Find parent of delete node
        if(pre->IntData>current->IntData){    //After remove delete node. The parent node will link to NULL.
            pre->Llink=NULL;
            clear=current;
            delete clear;
            Node_Number--;
            return;
        }else{
            pre->Rlink=NULL;
            clear=current;
            delete clear;
            Node_Number--;
            return;
        }    
    }
    pre=FindFather(DeleteData);
    if(current->Llink==NULL){    
        if(((current->Rlink)->Llink==NULL)&&((current->Rlink)->Rlink==NULL)){    //if the node we want to delete is only have one child node 
            clear=current;
            if(pre->IntData>current->IntData){    //parent node will link to the child of delete node 
                current=current->Rlink;
                pre->Llink=current;
                delete clear;
                Node_Number--;
                return;
            }else{    //parent node will link to the child of delete node 
                current=current->Rlink;    
                pre->Rlink=current;
                delete clear;
                Node_Number--;
                return;
            }
        }
    }else if(current->Rlink==NULL){
        if((current->Llink)->Llink==NULL&&(current->Llink)->Rlink==NULL){    //if the node we want to delete is only have one child node 
            clear=current;
            if(pre->IntData>current->IntData){    //parent node will link to the child of delete node 
                current=current->Llink;
                pre->Llink=current;
                delete clear;
                Node_Number--;
                return;
            }else{    //parent node will link to the child of delete node 
                current=current->Llink;
                pre->Rlink=current;
                delete clear;
                Node_Number--;
                return;
            }
        }
    }

    temp=current;    
    temp=temp->Llink;    
    if(temp->Rlink==NULL){    
        pre=FindFather(current->IntData);
        temp->Rlink=current->Rlink;
        if(temp->IntData<pre->IntData){
            pre->Llink=temp;
        }else{
            pre->Rlink=temp;
        }
        clear=current;
        delete clear;
        Node_Number--;
    }else{
        while(temp->Rlink!=NULL){
            temp=temp->Rlink;
        }
            pre=FindFather(temp->IntData);
            if(temp->Llink==NULL){
                pre->Rlink=NULL;
            }else{
                pre->Rlink=temp->Llink;
            }
            temp->Llink=current->Llink;
            temp->Rlink=current->Rlink;
            pre=FindFather(current->IntData);
            if(temp->IntData<pre->IntData){
            pre->Llink=temp;
            }else{
            pre->Rlink=temp;
            }
            clear=current;
            delete clear;
            Node_Number--;
    }
}

void BST::Sort(){
    if(root==NULL){
        cout<<"The tree is empty!"<<endl;
        return;
    }
    STACK=new TreeNode[Node_Number];    //Create a structure array as a stack!
    PopCount=0;
    current=root;

    
    while(1){    // Non-Recursive of inorder .The order is follow this rule. parent,leftchild,rightchild
        if(current!=NULL){
            push(current);
            current=current->Llink;
        }else{
                
                current=STACK[Top].Rlink;
                pop();
                PopCount++;
        }
        if(PopCount==Node_Number){
            cout<<endl;
            break;
        }
    }
    delete []STACK;
}

void BST::Search(){
    int num=0;
    cout<<"Please Enter the Integer"<<endl;
    cin>>num;
    if(SearchNumber(num)!=NULL){
        cout<<"That data does exist in tree!"<<endl;
    }else{
        cout<<"That data doesn't exist in tree!"<<endl;
    }
}


TreeNode* BST::SearchNumber(int num){    //Search a number
    TreeNode *temp;
    temp=root;
    while(temp!=NULL){
        if(temp->IntData==num){
            return temp;
        }else if(temp->IntData<num){
            temp=temp->Rlink;
        }else{
            temp=temp->Llink;
        }
    }
    return temp;
}

TreeNode* BST::FindFather(int num){    //Search parent
    TreeNode *Find;
    Find=root;
    while(Find!=NULL){
        if(Find->Llink!=NULL){
            if(Find->Llink->IntData==num){
                return Find;
            }
        }
        if(Find->Rlink!=NULL){
            if(Find->Rlink->IntData==num){
                return Find;
            }
        }
        if(num<Find->IntData){
            Find=Find->Llink;
        }else{
            Find=Find->Rlink;
        }
    }
}

void BST::push(TreeNode *temp){    
    if(Top==Node_Number-1){
        //cout<<"堆疊已滿"<<endl;
    }else{
        Top++;
        STACK[Top]=*temp;
    }
}

void BST::pop(){
        cout<<STACK[Top].IntData<<"\t";
        Top--;
}

void BST::inorder(TreeNode *D){    //Recursive of inorder
    if(D!=NULL){
        inorder(D->Llink);
        cout<<D->IntData<<endl;
        inorder(D->Rlink);
    }
}

void BST::ClearMemory(TreeNode *D){
    if(D!=NULL){
        ClearMemory(D->Llink);
        ClearMemory(D->Rlink);
        delete D;
    }
}



///main///

#include <iostream>
#include "BST.h"
using namespace std;

int main()
{
    char option;
    BST bst;
    while(1){
        cout<<"======================"<<endl;
        cout<<"1.Add Integer"<<endl;
        cout<<"2.Delete Integer"<<endl;
        cout<<"3.Search Integer"<<endl;
        cout<<"4.Show the result of sort"<<endl;
        cout<<"5.Quit"<<endl;
        while(cin.get(option)&&option=='\n');
        switch(option){
            case '1':bst.Add();
                break;
            case '2':bst.Delete();
                break;
            case '3':bst.Search();
                break;
            case '4':bst.Sort();
                break;
            case '5':cout<<"Quit Now"<<endl;
                return 0;
        }
    }
}


By Victor ; )

2013年1月25日

Circular Linked List in C++

Circular Linked List 跟一般的 Double linked list 幾乎一模一樣,

不同之處在於第一個節點的左 link 並非指向null,而是改成指向最後一個節點,

而同樣的最後一個節點之右 link 也並非指向null,而是改成指向第一個節點,

這樣就形成了一個循環的鏈結串列,稱之 Circular Linked List !

如下圖所示:



加入與刪除都如同前一篇,但是頭端與尾端會有所不同,因為其 link 不再是 null

http://vi-ctor.blogspot.tw/2013/01/double-linked-list-using-c.html

or

http://dsapn.blogspot.tw/2013/01/double-linked-list-using-c.html

接下來不囉嗦直接看Code吧!!  我覺得我好像寫得太麻煩了,應該可以寫得更簡單

,有問題還請指教!

///CLL.h///


#ifndef CLL_H
#define CLL_H
#include <iostream>

class CLL{
private:
    struct DataNode *head;
    struct DataNode *tail;
    struct DataNode *current;
    struct DataNode *ptr;
    struct DataNode *clear;
    char DeleteData;
    char InsertData;
public:
    CLL();
    ~CLL();
    void Add();
    void Insert();
    void List();
    void Delete();
};
#endif


///CLL.cpp///

#include "CLL.h"
using namespace std;
struct DataNode{
    char CharData;
    struct DataNode *Llink;
    struct DataNode *Rlink;
};

CLL::CLL(){
    head=new DataNode;
    current=new DataNode;
    tail=new DataNode;
    head->Llink=NULL;
    head->Rlink=NULL;
    tail->Llink=NULL;
    tail->Rlink=NULL;
    current->Llink=NULL;
    current->Rlink=NULL; 
}

CLL::~CLL(){
    if(head->Rlink==NULL){
        delete head;
        delete tail;
        delete current;
    }else{
        (tail->Rlink)->Rlink=NULL;
        delete tail;
        current=head;
        while(current!=NULL){
            clear=current;
            current=current->Rlink;
            delete clear;
        }
        delete current;
    }
    cout<<"已經清除記憶體..."<<endl;
    system("Pause");
}

void CLL::Add(){
    ptr=new DataNode;
    cout<<"請輸入資料"<<endl;
    cin>>ptr->CharData;
    if(head->Rlink==NULL){
        head->Rlink=ptr;
        tail->Rlink=ptr;        //將頭與尾端指向第一節點
        ptr->Llink=ptr;        //指回自己
        ptr->Rlink=ptr;
    }else{
        current=head->Rlink;    
        current->Llink=ptr;
        ptr->Rlink=current;
        ptr->Llink=tail->Rlink;
        (tail->Rlink)->Rlink=(head->Rlink)->Llink;
        head->Rlink=ptr;
    }
}

void CLL::Insert(){
     if(head->Rlink==NULL){
        cout<<"linklist為空,無法插入"<<endl;
    }else{
        ptr=new DataNode;
        cout<<"請輸入資料"<<endl;
        cin>>ptr->CharData;
        List();
        cout<<"想在哪筆資料的左邊插入資料?:"<<endl;
        cin>>InsertData;
        current=head->Rlink;
        if(current->CharData==InsertData){    //先處理頭端
            current->Llink=ptr;
            ptr->Rlink=current;
            ptr->Llink=tail->Rlink;
            (tail->Rlink)->Rlink=(head->Rlink)->Llink;
            head->Rlink=ptr;
        }
        current=current->Rlink;
        while(current!=head->Rlink){        //處理非頭端
            if(current->CharData==InsertData){
                (current->Llink)->Rlink=ptr;
                ptr->Llink=current->Llink;
                current->Llink=ptr;
                ptr->Rlink=current;
                break;
            }else{
                current=current->Rlink;    //前進
            }
        }
     }
}

void CLL::Delete(){
    List();
    cout<<"請輸入欲刪除資料:"<<endl;
    cin>>DeleteData;
    current=head->Rlink;
    if(current->CharData==DeleteData&&current->Rlink!=current){        //處理頭端且為單一節點
        (current->Rlink)->Llink=tail->Rlink;
        head->Rlink=current->Rlink;
        (tail->Rlink)->Rlink=head->Rlink;
        clear=current;
        delete clear;
    }else if(current->CharData==DeleteData){    //處理頭端且非單一節點
        head->Rlink=NULL;
        clear=current;
        delete clear;
    }else {
        current=current->Rlink;
        while(current!=head->Rlink){
            if(current->CharData==DeleteData){
            if(current==tail->Rlink){        //處理尾端
                (current->Llink)->Rlink=head->Rlink;
                (head->Rlink)->Llink=current->Llink;
                tail->Rlink=current->Llink;
                clear=current;
                current=current->Rlink;
                delete clear;
            }else{        //處理非頭非尾端
                (current->Llink)->Rlink=current->Rlink;
                (current->Rlink)->Llink=current->Llink;
                clear=current;
                current=current->Rlink;
                delete clear;
            }
            }else{
                current=current->Rlink;
            }
        }
    }

}

void CLL::List(){
    if(head->Rlink==NULL){
        cout<<"linklist為空"<<endl;
    }else{
        current=head->Rlink;
        cout<<"目前資料有:"<<endl;
        cout<<(tail->Rlink)->CharData<<" ";
        cout<<"<-"<<current->CharData<<"->";
        current=current->Rlink;
        while(current!=head->Rlink){
            cout<<" <- "<<current->CharData<<" -> ";
            current=current->Rlink;
        }
        cout<<(head->Rlink)->CharData<<endl;
    }
}



///main///

#include <iostream>
#include "CLL.h"
using namespace std;

int main()
{
    char option;
    CLL cll;
    while(1){
        cout<<"======"<<endl;
        cout<<"1.依序新增資料"<<endl;
        cout<<"2.在某筆資料前插入資料"<<endl;
        cout<<"3.刪除"<<endl;
        cout<<"4.顯示"<<endl;
        cout<<"5.結束"<<endl;
        while(cin.get(option)&&option=='\n');
        switch(option){
            case '1':cll.Add();
                break;
            case '2':cll.Insert();
                break;
            case '3':cll.Delete();
                break;
            case '4':cll.List();
                break;
            case '5':cout<<"程式結束"<<endl;
                return 0;
        }
    }
}


By Victor

2013年1月21日

Double linked list Using C++

Double linked list (雙向鏈結串列)

結構為:

LLink為指向前一個Node,RLink為指向下一個Node

優點:
任何一個Node可得知前後的Node

較為強固

缺點:
插入需更動4個指標,麻煩

刪除需更動兩個指標,麻煩



Double linked list 的插入如下圖所示:


Double linked list 的刪除如下圖所示:
這邊要注意一下,插入或刪除節點時,會因為節點位置而造成策略不同,如頭端。

下列為使用C++實作 Double linked list 之程式碼,功能有 循序加入節點、加入任意節點、

刪除節點、印出,這次程式碼有加上註解...

///DLL.h///

#ifndef DLL_H
#define DLL_H
#include <iostream>

class DLL{
private:
    struct DataNode *head;
    struct DataNode *current;
    struct DataNode *ptr;
    struct DataNode *clear;
    char DeleteData;
    char InsertData;
public:
    DLL();
    ~DLL();
    void Add();
    void Insert();
    void List();
    void Delete();
};

#endif

///DLL.cpp///
#include "DLL.h"
using namespace std;

struct DataNode{
    char CharData;
    struct DataNode *Llink;
    struct DataNode *Rlink;
};

DLL::DLL(){
    head=new DataNode;
    current=new DataNode;
    head->Llink=NULL;
    head->Rlink=NULL;
    current->Llink=NULL;
    current->Rlink=NULL;        //初始化
}

DLL::~DLL(){
    if(head->Rlink==NULL){
        delete head;
        delete current;
    }else{
        current=head;
        while(current!=NULL){
            clear=current;
            current=current->Rlink;
            delete clear;
        }
        delete current;
    }
    cout<<"已經清除記憶體..."<<endl;
    system("Pause");
}

void DLL::Add(){
    ptr=new DataNode;
    cout<<"請輸入資料"<<endl;
    cin>>ptr->CharData;
    if(head->Rlink==NULL){    //判斷是否為空,如為空則代表該資料為頭端
        head->Rlink=ptr;
        ptr->Llink=NULL;
        ptr->Rlink=NULL;
    }else{    //不為空則需要更動4根指標
        current=head->Rlink;
        current->Llink=ptr;
        ptr->Rlink=current;
        ptr->Llink=NULL;
        head->Rlink=ptr;
    }
}

void DLL::Insert(){
    if(head->Rlink==NULL){
        cout<<"linklist為空,無法插入"<<endl;
    }else{
        ptr=new DataNode;
        cout<<"請輸入資料"<<endl;
        cin>>ptr->CharData;
        List();
        cout<<"想在哪筆資料的左邊插入資料?:"<<endl;
        cin>>InsertData;
        current=head->Rlink;
        while(current!=NULL){
            if(current->CharData==InsertData){    //判斷該位置是否為我們要插入的資料
                if(current->Llink==NULL){    //插入資料為頭端
                    current->Llink=ptr;
                    ptr->Rlink=current;
                    ptr->Llink=NULL;
                    head->Rlink=ptr;
                    break;
                }else{    //插入資料為其他時,而因是插在某筆資料之前所以不會有尾端之情況
                    (current->Llink)->Rlink=ptr;
                    ptr->Llink=current->Llink;
                    current->Llink=ptr;
                    ptr->Rlink=current;
                    break;
                }
            }else{
                current=current->Rlink;    //前進
            }
        }
    }
}

void DLL::Delete(){
    List();
    cout<<"請輸入欲刪除資料:"<<endl;
    cin>>DeleteData;
    current=head->Rlink;
    while(current!=NULL){
        if(current->CharData==DeleteData){    //先判斷該位置是否是我們需要刪掉的資料
            if(current->Llink==NULL&&current->Rlink==NULL){    //判斷需要刪除資料的位置,因為位置的不同動作也有所不同,此判斷為只剩單一節點
                clear=current;
                current=current->Rlink;
                head->Rlink=NULL;
                clear->Llink=NULL;
                clear->Rlink=NULL;
                delete clear;    
            }else if(current->Llink==NULL){    //刪除資料為頭端
                (current->Rlink)->Llink=NULL;
                clear=current;
                current=current->Rlink;
                head->Rlink=current;
                clear->Llink=NULL;
                clear->Rlink=NULL;
                delete clear;    
            }else if(current->Rlink==NULL){    //刪除資料為尾端
                (current->Llink)->Rlink=NULL;
                clear=current;
                current=current->Rlink;
                clear->Llink=NULL;
                clear->Rlink=NULL;
                delete clear;    
            }else{    //刪除資料為中間節點
                (current->Llink)->Rlink=current->Rlink;
                (current->Rlink)->Llink=current->Llink;
                clear=current;
                current=current->Rlink;
                clear->Llink=NULL;
                clear->Rlink=NULL;
                delete clear;
            }
        }else{
            current=current->Rlink;    //前進
        }
    }
}

void DLL::List(){
    if(head->Rlink==NULL){
        cout<<"linklist為空"<<endl;
    }else{
        current=head->Rlink;
        cout<<"目前資料有:"<<endl;
        cout<<"null";
        while(current!=NULL){
            cout<<" <- "<<current->CharData<<" -> ";
            current=current->Rlink;
        }
        cout<<"null"<<endl;
    }
}

///main///
#include <iostream>
#include "DLL.h"
using namespace std;

int main()
{
    char option;
    DLL dll;
    while(1){
        cout<<"======"<<endl;
        cout<<"1.依序新增資料"<<endl;
        cout<<"2.在某筆資料前插入資料"<<endl;
        cout<<"3.刪除"<<endl;
        cout<<"4.顯示"<<endl;
        cout<<"5.結束"<<endl;
        while(cin.get(option)&&option=='\n');
        switch(option){
            case '1':dll.Add();
                break;
            case '2':dll.Insert();
                break;
            case '3':dll.Delete();
                break;
            case '4':dll.List();
                break;
            case '5':cout<<"程式結束"<<endl;
                return 0;
        }
    }
}

by Victor

Single linked list using C++

linked list (鏈結串列)

為Node所構成之集合


優點:

1.Node之間允許memory不連續配置
2.不同Node間可存放型態不同的資料
3.插入刪除元素容易


缺點:

多了point的空間

只能夠循序存取


========================================================================


Array在宣告時一定要給予大小,

雖然說可動態的宣告Array,但是也會在執行時要求其大小,很容易造成空間的浪費,

而鏈結串列相較之下不會有此問題,根據不同的情況常見的鏈結串列有:

Single linked list、Circular linked list、Double linked list , 本篇是實作基本的 Single linked list,

其功能包含 循序加入資料、插入任意資料、刪除任意資料、查看所有資料。

而一個 Single linked list 大致上可用圖解畫成這樣:




而節點的宣告方式大致上如下圖所示,隨著需求不同而不同

struct Node
{
    Type data;
    Node *next;
};


插入節點可表示圖解為:
刪除節點可表示圖解為:

以下是Single linked list利用C++所實作的簡易程式碼

///SLL.h///
#ifndef SLL_H
#define SLL_H
#include <iostream>

class SLL{
private:
    struct DataNode *head;
    struct DataNode *current;
    struct DataNode *previous;
    struct DataNode *ptr;
    struct DataNode *clear;
    char DeleteData;
    char InsertData;
public:
    SLL();
    ~SLL();
    void Add();
    void Insert();
    void List();
    void Delete();
};

#endif

///SLL.cpp///
#include "SLL.h"
using namespace std;

struct DataNode{
    char CharData;
    struct DataNode *next;
};

SLL::SLL(){
    head=new DataNode;
    current=new DataNode;
    previous=new DataNode;
    head->next=NULL;
    current->next=NULL;
}

SLL::~SLL(){
    if(head->next==NULL){
        delete head;
        delete current;
        delete previous;
    }else{
        current=head;
        while(current!=NULL){
            clear=current;
            current=current->next;
            delete clear;
        }
        delete current;
        delete previous;
        cout<<"已經清除記憶體..."<<endl;
        system("Pause");
    }
}

void SLL::Add(){
    ptr=new DataNode;
    cout<<"請輸入資料"<<endl;
    cin>>ptr->CharData;
    if(head->next==NULL){
        head->next=ptr;
        ptr->next=NULL;
    }else{
        ptr->next=head->next;
        head->next=ptr;
    }
}

void SLL::Insert(){
    if(head->next==NULL){
        cout<<"linklist為空,無法插入"<<endl;
    }else{
        ptr=new DataNode;
        cout<<"請輸入資料"<<endl;
        cin>>ptr->CharData;
        List();
        cout<<"想在哪筆資料後插入資料?:"<<endl;
        cin>>InsertData;
        current=head->next;
        while(current!=NULL){
            if(current->CharData==InsertData){
                previous->next=ptr;
                ptr->next=current;
                break;
            }
            current=current->next;
            previous=previous->next;
        }
        List();
    }
}

void SLL::List(){
    if(head->next==NULL){
        cout<<"linklist為空"<<endl;
    }else{
        previous=head;
        current=head->next;
        cout<<"目前資料為:"<<endl;
        while(current!=NULL){
            cout<<current->CharData<<"->";
            current=current->next;
        }
        cout<<"null"<<endl;
    }
}

void SLL::Delete(){
    if(head->next==NULL){
        cout<<"linklist為空"<<endl;
    }else{
        List();
        cout<<"請輸入欲刪除資料:"<<endl;
        cin>>DeleteData;
        current=head->next;
        while(current!=NULL){
            if(current->CharData==DeleteData){
                previous->next=current->next;
                current->next=NULL;
                clear=current;
                delete clear;
                current=previous->next;
            }else{
                current=current->next;
                previous=previous->next;
            }
        }
    }
}

///main///
#include <iostream>
#include "SLL.h"
using namespace std;

int main()
{
    char option;
    SLL sll;
    while(1){
        cout<<"======"<<endl;
        cout<<"1.依序新增資料"<<endl;
        cout<<"2.在某筆資料前插入資料"<<endl;
        cout<<"3.刪除"<<endl;
        cout<<"4.顯示"<<endl;
        cout<<"5.結束"<<endl;
        while(cin.get(option)&&option=='\n');
        switch(option){
            case '1':sll.Add();
                break;
            case '2':sll.Insert();
                break;
            case '3':sll.Delete();
                break;
            case '4':sll.List();
                break;
            case '5':cout<<"程式結束"<<endl;
                return 0;
        }
    }
}


結論:

Single linked list 雖然新增予刪除節點方便O(1),而也比Array省空間,

但是因為沒有索引值而導致要歷經每個節點才可找到特定值,n筆資料的話則 花費O(n)

也需花費儲存指標的記憶體,不過在某些情況下非常方便,可動態的加入刪除資料!!

By   Victor

Queue and CircularQueue in C++ ; )


Queue,就是佇列 (廢話),

Queue具有以下特性:

1. 具有FIFO性質
2. 插入與刪除在不同端

下圖為Queue之操作模式:



加入資料一律在尾端,取出資料一律在頭端,

則可達到上述兩種特性。


Queue的應用:

1. 正常的Queue

2. Priority Queue

   ->插入任意優先權的工作
   ->刪除最大或最小權值之工作

3. Double-ended Priority Queue

   ->插入隨意權值
   ->可刪除最大最小權值

4. OS中的排班法則、日常排隊、BFS (廣度優先)


而一般的Queue會有一些空間上的問題,

顯示Queue已滿,但是其實並沒有滿,



雖然有解,但是假如有n個資料就要搬動n次。


而 CircularQueue 可以解決此問題。

CircularQueue如下圖所示,長得很像甜甜圈。



特色:

插入與刪除計算複雜度為 big-O (1)

操作判斷與Queue相似

缺點:這種傳統的 CircularQueue 只可利用 n-1格。

下面為使用Array實作 CircularQueue  (某家公司在面試時考出來!)

初始化: Font 與 Rear 開始位置為 N-1



插入第一筆資料後

所以:


 接著加入b c d 後


再繼續加入則會顯示已滿!

會先做Front與Rear=(Rear+1)mod SIZE是否為同一格的檢查,

假如為同一格則Rear往後退一格(Rear=Rear-1)(先前進作檢查,已滿則後退)

而假如Front與Rear=(Rear+1)mod SIZE為同一格,而Front又為0時,

這時假如做(Rear=Rear-1)會發生 Real為-1,所以在這種狀況下

要指定位置為SIZE-1。
刪除資料:
Front已經變0了。(我現在才發現有些英文字打錯了.......反正看得懂就好對吧!)

接下來就自己根據程式碼追追看了喔。

ps. 讀取資料那邊會這樣設計是有原因的,

之前一直有錯誤,想了一會才改成現在的樣子!






=======CQ.h=======
#ifndef CQ_H
#define CQ_H
#include <iostream>

class CQ
{
private:
    int Font;
    int Rear;
public:
    CQ();
    ~CQ();
    void Add();
    void List();
    void Delete();
    char *Arr;
    int MAX;
};

#endif


=======CQ.cpp=======
#include "CQ.h"
using namespace std;
CQ::CQ(){
    cout<<"請輸入CircularQueue大小"<<endl;
    cin>>MAX;
    Font=MAX-1;
    Rear=MAX-1;
    Arr=new char[MAX];
}

CQ::~CQ(){
    delete []Arr;
}

void CQ::Add(){
    Rear=(Rear+1)%MAX;
    if(Rear==Font){
        if(Rear==0){
            Rear=MAX-1;
        }else{
            Rear=Rear-1;
        }
        cout<<"CircularQueue已滿!!"<<endl;
        
    }else{
        cout<<"請輸入資料"<<endl;
        cin>>Arr[Rear];
    }
}

void CQ::Delete(){
    if(Rear==Font){
        cout<<"CircularQueue為空!!"<<endl;
    }else{
        Font=(Font+1)%MAX;
        cout<<"刪除的資料為:"<<Arr[Font]<<endl;
    }
}

void CQ::List(){
    if(Rear==Font){
        cout<<"CircularQueue為空!!"<<endl;
    }else{
        cout<<"Font="<<Font<<endl;
        cout<<"Rear="<<Rear<<endl;
        for(int i=(Font+1)%MAX;i!=(Rear+1)%MAX;i=++i%MAX){
        cout<<"第"<<i<<"格資料為:"<<Arr[i]<<endl;
        }
    }
    
    
}


=======main=======
#include <iostream>
#include "CQ.h"

using namespace std;
int main()
{
    char option;
    CQ cq;
    while(1){
        cout<<"======"<<endl;
        cout<<"1.插入"<<endl;
        cout<<"2.刪除"<<endl;
        cout<<"3.顯示"<<endl;
        cout<<"4.結束"<<endl;
        while(cin.get(option)&&option=='\n');
        switch(option){
            case '1':cq.Add();
                break;
            case '2':cq.Delete();
                break;
            case '3':cq.List();
                break;
            case '4':cout<<"程式結束"<<endl;
                     system("PAUSE");
                return 0;
        }
    }
}



By Victor

C++ 使用Array實作Stack

Stack,就是堆疊,他的構造像是一個籃子,不管怎麼樣你都只能對

最上面的資料去做處理。 而他只有兩種操作模式:1.POP 2.PUSH

POP就是取出堆疊最上層的資料,而PUSH就是塞入資料至資料最上層。

如圖所示。


本篇是利用Array達到stack的功能。

簡單的範例如下所示:

一開始先決定堆疊大小

分別PUSH a b c
再PUSH則會告知堆疊已滿 (因為超出堆疊限定大小)
POP時顯示被POP的資料

可列出目前堆疊資料


=========StackObject.h============
#ifndef STACKOBJECT_H
#define STACKOBJECT_H
#include <iostream>

class StackObject{
public:
    StackObject();
    ~StackObject();
    void Add();
    void Delete();
    void List();
private:
    int Top;
    char *Arr;
    int MAX;
};


#endif


=========StackObject.cpp============
#include "StackObject.h"
using namespace std;
StackObject::StackObject(){
    Top=-1;
    cout<<"請輸入堆疊大小"<<endl;
    cin>>MAX;
    Arr=new char[MAX];
}

StackObject::~StackObject(){
    delete []Arr;
}

void StackObject::Add(){
    if(Top==MAX-1){
        cout<<"堆疊已滿"<<endl;
    }else{
        Top++;
        cout<<"請輸入字元"<<endl;
        cin>>Arr[Top];
        cout<<"輸入完畢謝謝!"<<endl;
    }
}


void StackObject::Delete(){
    if(Top<0){
        cout<<"堆疊為空,並無資料"<<endl;
    }else{
        cout<<"刪除的資料為:"<<Arr[Top]<<endl;
        Top--;
    }
}

void StackObject::List(){
    if(Top<0){
        cout<<"堆疊為空,並無資料"<<endl;
    }else{
        for(int i=0;i<Top+1;i++){
            cout<<"第"<<i+1<<"筆資料為:"<<Arr[i]<<endl;
        }
    }
}


=========main============
#include <iostream>
#include "StackObject.h"
using namespace std;
int main()
{
    char option;
    StackObject stack;
    while(1){
        cout<<"=========="<<endl;
        cout<<"1.PUSH"<<endl;
        cout<<"2.POP"<<endl;
        cout<<"3.List All Data"<<endl;
        cout<<"4.Quit"<<endl;
        while(cin.get(option)&&option=='\n');
            switch(option){
            case '1':stack.Add();
                break;
            case '2':stack.Delete();
                break;
            case '3':stack.List();
                break;
            case '4':
                system("PAUSE");
                return 0;
            }
    }
}

by Victor

計算複雜度

當我們想要與其他人寫的演算法去做比較的時候,常常會使用"計算複雜度"以及"空間複雜

度"去做比較,這種比較方法比較科學。  那我們為什麼不用運行時間來比較呢?

很簡單!是因為我們每個人的電腦設備都不同,而該電腦在執行時背後很有可能正在執行其他

的程式,這時也會導致不準確。   舉個例子,A演算法執行在一般的電腦上跑了10秒,但是執

行在超級電腦的B演算法可能連1秒都不到,但是難道可以說B演算法比A演算法好嗎?

懂我的意思嗎?


下面是一個矩陣相加例子:




for(int i=0;i<n;i++){ //n+1
for(int j=0;j<n;j++){ //n(n+1)
MatrixResult[i][j]=MatrixA[i][j]+MatrixB[i][j]; //n2
}
}


for迴圈會執行n+1次,因為當 i=n 時 for 迴圈會進行一次比較,這也算一次。

所以計算複雜度為:  2n2+2n+1  = >  Big-O( n)



Big-O定義為: f ( n ) = Big-O ( g ( n ) ),若且唯若存在一正整數 c 及 n0

,使得 f ( n ) < = c * g ( n ),對所有的n,n > = n0


根據定義,也就是說

f(n)= 2n^2+2n+1 ; 存在C=3 , n0=3 使得 n>=3後 2n^2+2n+1 <=3n^2 

所以 f(n)=> big-O (n^2)



By   Victor