SLIDE1

Showing posts with label cau truc cay. Show all posts
Showing posts with label cau truc cay. Show all posts

Thursday, June 11, 2015

hàm xóa node trong cây nhị phân tìm kiếm

hàm xóa node trong cây nhị phân tìm kiếm
void thaythe(tree &t,node *p)
{
    if(t->left) thaythe(t->left,p);
    //nếu nhánh bên trái còn tức là khác NULL thì tiếp tực nhảy đến nhánh bến trái
    //cho đến khi nào nó là cực trái thì thôi
    else//nó đã là node cực trái
    {
        p->key=t->key;
        //p là con trỏ truyền vào, mọi thay đỏi về bộ nhớ, ô nhớ hay giá trị đều thay đỏi trên
        //hàm xoa(tree &t,int x) đã gọi nó.
        //lúc này p là node cần xóa ở hàm xóa, ta không xóa node mà thay thế giá trị cho nó
        //rồi chuyển nó đến 1 ô nhớ khác, 
        //ô nhớ mà t đang tìm để thay thế để hàm xoa() gọi delete nó.
        p=t;//node t là node ta đã tìm ra để thay thế 
        //nên p=t; tức là sẽ xóa T thay cho p ban đầu
        //nên p(node sẽ xóa ở hàm ngoài) nhảy đến ô nhớ của node thay thế là node T , p=t;
        t=t->right;
        //vì t sẽ bị xóa thông qua p nên t phải nhay đến nhánh bên phải 
        //để làm liến mạch liên kết với cha như đã lý giải ở hàm xóa
        //vì sao lại trỏ right là không phải trỏ left?
        //vì T là node thay thế, là node cực trái, 
        //tức nhánh trái = NULL còn nhánh phải có thể khác NULL
        //hoắc bằng NULL, t không cần xác định, chỉ cần 
        //trỏ t->right để làm liền mạch liên kết đến node cha đã gọi đến nó
        //là ok.
    }
}
void xoa(tree &t,int x)//hàm xóa node trong cây nhị phân tìm kiếm
{
    if(t)//nếu cây t!=NULL
    {
        if(x<t->key) xoa(t->left,x);//nếu x < key xóa bên trái
        else if(x>t->key) xoa(t->right,x);//xóa bên phải
        else//đã tìm thấy node cần xóa
        {
            node *p=t;//gán node cần xóa cho p
            if(t->left==NULL) t=t->right;
            //nếu node cần xóa có 1 cây con bên phải
            else if(t->right==NULL) t=t->left;
            //hoặc 1 cây con bên trái
            //thì T được truyền vào trong đối số hàm nhảy sang trái hoăc sang phải như trên
            //vì sao nó liên kết được với node cha??
            //vì node cha đang trỏ đến con trỏ t (tree &t) 
            //ở dạng tham chiếu luôn nên mọi thay đổi trên t
            //thì đều thay đổi trên cấu trúc của node cha, node gọi đến hàm này
            //vì thế node cha của node cần xóa hiện tại 
            //sẽ trỏ đến t, và khi t=t->right; thì
            //node cha của node cần t cần xóa vẫn đang trỏ 
            //đến t với giá trị là ô địa chỉ mới t->right;
            else thaythe(t->right,p);
            //nếu ndoe t cần xóa có 2 nhánh con thì tìm node cực trái của nhánh phải
            //hoặc ngược lại cũng có thể được
            delete p;
        }
    }
    //lưu ý cần nhớ.
    //khi đối số của hàm là còn trỏ hoặc tham chiếu 
    //thì mọi thay đổi trên nó đều thay đổi đến biến của hàm đã gọi nó, 
    //thay đổi đến cụ diện chung của biến, của hàm đã gọi nó.
}

Tuesday, May 26, 2015

cấu trúc cây nhị phân tìm kiếm và các thao tác trên cây

cấu trúc cây nhị phân tìm kiếm và các thao tác trên cây. định nghĩa, và các thao tháo cần thiết phải có khi cài đặt 1 cay nhị phân tìm kiếm

Ðịnh nghĩa cây nhị phân tìm kiếm


Cây nhị phân
Bảo đảm nguyên tắc bố trí khoá tại mỗi nút:
Các nút trong cây trái nhỏ hơn nút hiện hành
Các nút trong cây phải lớn hơn nút hiện hành


Ưu điểm của cây nhị phân tìm kiếm


Nhờ trật tự bố trí khóa trên cây :
Định hướng được khi tìm kiếm
Cây gồm N phần tử :
Trường hợp tốt nhất h = log2N
Trường hợp xấu nhất h = Ln
Tình huống xảy ra trường hợp xấu nhất ?


Cấu trúc dữ liệu của cây nhị phân tìm kiếm


Cấu trúc dữ liệu của 1 nút
    typedef struct tagTNode
    {  
        int Key; //trường dữ liệu là 1 số nguyên
        struct tagTNode *pLeft;
        struct tagTNode *pRight;
    }TNode;
Cấu trúc dữ liệu của cây
    typedef TNode *TREE;

Các thao tác trên cây nhị phân tìm kiếm



Tạo 1 cây rỗng
Tạo 1 nút có trường Key bằng x
Thêm 1 nút vào cây nhị phân tìm kiếm
Xoá 1 nút có Key bằng x trên cây
Tìm 1 nút có khoá bằng x trên cây


Tạo cây rỗng


Cây rỗng -> địa chỉ nút gốc bằng NULL
    void CreateTree(TREE &T)
    {
        T=NULL;
    }

Tạo 1 nút có Key bằng x


TNode *CreateTNode(int x)
{
        TNode *p;
        p = new TNode; //cấp phát vùng nhớ động
        if(p==NULL)
            exit(1); // thoát
        else
        {
            p->key = x; //gán trường dữ liệu của nút = x
            p->pLeft = NULL;
            p->pRight = NULL;
        }
        return p;
}


Thêm một nút x


Rằng buộc: Sau khi thêm cây đảm bảo là cây nhị phân tìm kiếm.
int insertNode(TREE &T, Data X)
{   if(T)
    {   if(T->Key == X) return 0;
        if(T->Key > X) return insertNode(T->pLeft, X);
        else    return insertNode(T->pRight, X);}
        T   = new TNode;
        if(T == NULL)   return -1;
        T->Key  = X;
        T->pLeft =T->pRight = NULL;
    return 1;
}

Tìm nút có khoá bằng x (không dùng đệ quy)


TNode * searchNode(TREE Root,  Data x)
{       Node *p = Root;
        while (p != NULL)
        {   if(x == p->Key) return p;
            else  
            if(x < p->Key)  p = p->pLeft;
            else    p = p->pRight;
        }
        return NULL;
}

Tìm nút có khoá bằng x (dùng đệ quy)


TNode *SearchTNode(TREE T, int x)
{
    if(T!=NULL)
    {
        if(T->key==x)
            return T;
        else
            if(x>T->key)
                return SearchTNode(T->pRight,x);
            else
                return SearchTNode(T->pLeft,x);
    }
    return NULL;
}

Hủy 1 nút có khoá bằng X trên cây


Hủy 1 phần tử trên cây phải đảm bảo điều kiện ràng buộc của Cây nhị phân tìm kiếm
Có 3 trường hợp khi hủy 1 nút trên cây
TH1: X là nút lá
TH2: X chỉ có 1 cây con (cây con trái hoặc cây con phải)
TH3: X có đầy đủ 2 cây con
TH1: Ta xoá nút lá mà không ành hưởng đến các nút khác ttrên cây
TH2: Trước khi xoá x ta móc nối cha của X với con duy nhất cùa X.
TH3: Ta dùng cách xoá gián tiếp

Hủy 1 nút có 2 cây con


Ta dùng cách hủy gián tiếp, do X có 2 cây con
Thay vì hủy X ta tìm phần tử thế mạng Y. Nút Y có tối đa 1 cây con.
Thông tin lưu tại nút Y sẽ được chuyển lên lưu tại X.
Ta tiến hành xoá hủy nút Y (xoá Y giống 2 trường hợp đầu)
Cách tìm nút thế mạng Y cho X: Có 2 cách
 C1: Nút Y là nút có khoá nhỏ nhất (trái nhất) bên cây con phải X
C2: Nút Y là nút có khoá lớn nhất (phải nhất) bên cây con trái của X

Cài đặt thao tác xoá nút có trường Key = x


void DeleteNodeX1(TREE &T,int x)
{
    if(T!=NULL)
    {
        if(T->Key<x)    DeleteNodeX1(T->Right,x);
        else
        {
            if(T->Key>x)    DeleteNodeX1(T->Left,x);
            else  //tim thấy  Node có trường dữ liệu = x
            {   TNode *p;  
                p=T;
                if (T->Left==NULL)  T = T->Right;
                else
                {   if(T->Right==NULL)  T=T->Left;
                    else    ThayThe1(p, T->Right);// tìm bên cây con phải
                }
                delete p;
            }
        }
    }
    else    printf("Khong tim thay phan can xoa tu");
}

Hàm tìm phần tử thế mạng 


void ThayThe1(TREE &p, TREE &T)
{    if(T->Left!=NULL)
        ThayThe1(p,T->Left);
else
     {
        p->Key = T->Key;
        p=T;
        T=T->Right;
    }
}

cấu trúc cây trong lập trình c/c++

cấu trúc cây trong lập trình c/c++, cấu trúc cây rất quan trọng trong lập trình quản lý dữ liệu


Định Nghĩa Cây


Cây là một tập hợp T các phần tử (gọi là nút của cây), trong đó có một nút đặc biệt gọi là nút gốc, các nút còn lại được chia thành những tập rời nhau T1, T2, …,Tn theo quan hệ phân cấp, trong đó Ti cũng là 1 cây. Mỗi nút ở cấp i sẽ quản lý một số nút ở cấp i+1. Quan hệ này người ta gọi là quan hệ cha – con.

Một Số Khái Niệm


Bậc của một nút: là số cây con của nút đó .
Bậc của một cây: là bậc lớn nhất của các nút trong cây 
Nút gốc: là nút không có nút cha.
Nút lá: là nút có bậc bằng 0 .
Mức của một nút:
Mức (gốc (T) ) = 0.
Gọi T1, T2, T3, ... , Tn là các cây con của T0 : Mức (T1) = Mức (T2) = . . .  = Mức (Tn) = Mức (T0) + 1.
Độ dài đường đi từ gốc đến nút x: là số nhánh cần đi qua kể từ gốc đến x.

Một Số Tính Chất Của Cây Nhị Phân


Số nút nằm ở mức i  2i.
Số nút lá  2h-1, với h là chiều cao của cây.
Chiều cao của cây h  log2(N)
N = số nút trong cây
Số nút trong cây  2h-1.

Cấu Trúc Dữ Liệu Của Cây Nhị Phân


typedef struct tagTNode
{
Data Key; 
struct tagTNode *pLeft; struct tagTNode *pRight; 
}TNode;

typedef TNode *TREE;


Duyệt Cây Nhị Phân 


 Có 3 trình tự thăm gốc :
 Duyệt trước
 Duyệt giữa
 Duyệt sau
  Độ phức tạp O (log2(h))
    Trong đó h là chiều cao cây

Duyệt Trước 


void NLR(TREE Root)
{
if (Root != NULL)
{
<Xử lý Root>; //Xử lý tương ứng theo nhu cầu NLR(Root->pLeft);
NLR(Root->pRight);
}
}

Duyệt Giữa

void LNR(TREE Root)
{
if (Root != NULL)
{
LNR(Root->pLeft);
<Xử lý Root>; // Xử lý tương ứng theo nhu cầu 
LNR(Root->pRight);
}
}

Duyệt Sau

void LRN(TREE Root)
{
if (Root != NULL)
{
LRN(Root->pLeft);
LRN(Root->pRight);
<Xử lý Root>; // Xử lý tương ứng theo nhu cầu 
}
}

Saturday, May 16, 2015

tính giá trị biểu thức bằng cây nhị phân

lập trình c++ trính giá trị biểu thức toán học gồm số nguyên, dấu ngoặc (), phép toán +-*/ bằng phương pháp cây nhị phân.
#include<iostream>
#include<string>
using namespace std;
typedef struct tagnode
{
     string s;
     struct tagnode *left;
     struct tagnode *right;
}node;
node *taonode(string s)
{
     node *p=new node;
     if(p==NULL)
     {
          cout<<"khong du bo nho";
          system("pause");
          exit(1);
     }
     p->s=s;
     p->left=p->right=NULL;
     return p;
}
typedef node *cay;
void taocay(cay &t)
{
     t=NULL;
}
int vitridau(string s,int j)
{
     for(int i=j+1;i<s.size();i++)
          if(s[i]=='+' || s[i]=='-' || s[i]=='*' || s[i]=='/' || s[i]=='(')
               return i;
     return -1;
}
int timngoac(string s,int i)
{
     int j,dem=1;
     for(j=i+1;j<s.size();j++)
     {
          if(s[j]=='(') dem++;
          else if(s[j]==')') dem--;
          if(dem==0) return j;
     }
     return -1;
}
void xulyngoac(string &s)
{
     if(s[0]=='(')
     {
          int i=timngoac(s,0);
          if(i==s.size()-1)
          {
               s.erase(0,1);
               s.erase(s.size()-1,1);
          }
     }
}
void doidau(string &c)
{
     int x=0;
     do{
          x=vitridau(c,x);
          if(x!=-1)
          {
               if(c[x]=='(') x=timngoac(c,x);
               else if(c[x]=='-' && c[x-1]!='*' && c[x-1]!='/') c[x]='+';
               else if(c[x]=='+' && c[x-1]!='*' && c[x-1]!='/') c[x]='-';
               //chỉ đổi dấu + thành - và dấu - thành cộng khi nó là dấu của 1 số hạng
               //nếu nó dấu của 1 thừa số thì dữ nguyên không thay đổi gì cả mặc dù
               //dấu của node của cây tức s[i] là dấu - vì dấu của thừa số không liên quan đến số hạng
          }
     }while(x!=-1);
}
node *setcay(string s)
{
     xulyngoac(s);
     node *p;
     int k,j,x;
     string a,b,c;
     int i=vitridau(s,0);//tìm vị trí dấu đầu tiên trong biểu thức, có 2 trường hợp, có dấu và không có dấu
     if(s[0]=='(') i=0;
     if(i==-1)// trường hợp không có dấu
     {
          p=taonode(s);
          return p;
     }
     else//trường hợp có dấu, có 3 trường hợp nhỏ
     {
          if(s[i]=='+' || s[i]=='-')// dấu + hoặc -
          {
               a=s[i];
               p=taonode(a);
               b=s.substr(0,i);
               xulyngoac(b);
               c=s.substr(i+1,s.size()-i-1);
               xulyngoac(c);
               //đổi dấu các số hạng phía sau nếu s[i] là dấu -
               if(s[i]=='-') doidau(c);
               p->left=setcay(b);
               p->right=setcay(c);
          }
          else if(s[i]=='*' || s[i]=='/')//dấu * hoặc /
          {
               k=i;
               //tìm vị trí dấu + hoặc - phía sau dấu ngoặc nhưng nằm ngoài dấu ngoặc
               do{
                    k=vitridau(s,k);
                    if(k!=-1)
                    {
                         if(s[k]=='(') k=timngoac(s,k);
                         if(k>0 && (s[k]=='+' || s[k]=='-') && (s[k-1]!='*' && s[k-1]!='/')) break;
                    }
               }while(k!=-1);
               if(k==-1)//nếu không có thì node sẽ là dấu * hoặc / tại vị trí i ban đầu
               {
                    a=s[i];
                    p=taonode(a);
                    b=s.substr(0,i);
                    xulyngoac(b);
                    c=s.substr(i+1,s.size()-i-1);
                    xulyngoac(c);
                    p->left=setcay(b);
                    p->right=setcay(c);
               }
               else//nếu tìm thấy thì node là dấu tìm thấy
               {
                    a=s[k];
                    p=taonode(a);
                    b=s.substr(0,k);
                    xulyngoac(b);
                    c=s.substr(k+1,s.size()-k-1);
                    xulyngoac(c);
                    //doi dau +-
                    if(s[k]=='-') doidau(c);
                    p->left=setcay(b);
                    p->right=setcay(c);
               }
          }
          else if(s[i]=='(')//dấu mở ngoặc (
          {
               j=timngoac(s,i);//tìm vị trí dấu đóng ngoặc
               
               if(s[j+1]=='+' || s[j+1]=='-')//sau dấu đóng ngoặc là dấu + hoặc - thì node là dấu + hoặc -
               {
                    a=s[j+1];
                    p=taonode(a);
                    b=s.substr(0,j+1);
                    xulyngoac(b);
                    c=s.substr(j+2,s.size()-j-2);
                    xulyngoac(c);
                    //doi dau +-
                    if(s[j+1]=='-') doidau(c);
                    p->left=setcay(b);
                    p->right=setcay(c);
               }
               else if(s[j+1]=='*' || s[j+1]=='/')//nếu sau đóng ngoặc là * hoặc /
               {
                    k=j+1;
                    //tiếp tục tìm dấu + - phía sau nó mà nằm ngoài tất cả dấu ngoặc
                    do{
                         k=vitridau(s,k);
                         if(k!=-1)
                         {
                              if(s[k]=='(') k=timngoac(s,k);
                              if(k>0 && (s[k]=='+' || s[k]=='-') && (s[k-1]!='*' && s[k-1]!='/')) break;
                         }
                    }while(k!=-1);
                    if(k==-1)//nếu không tìm thấy thì node là dấu */ tại trí j+1
                    {
                         a=s[j+1];
                         p=taonode(a);
                         b=s.substr(0,j+1);
                         xulyngoac(b);
                         c=s.substr(j+2,s.size()-j-2);
                         xulyngoac(c);
                         p->left=setcay(b);
                         p->right=setcay(c);
                    }
                    else//nếu tìm thấy thì node là dấu tìm thấy
                    {
                         a=s[k];
                         p=taonode(a);
                         b=s.substr(0,k);
                         xulyngoac(b);
                         c=s.substr(k+1,s.size()-k-1);
                         xulyngoac(c);
                         //doi dau +-
                         if(s[j+1]=='-') doidau(c);
                         p->left=setcay(b);
                         p->right=setcay(c);
                    }
               }
          }
     }
     return p;
}
long atol(string s)
{
     long x=0,d=1;
     int j=0,k=0;
     if(s[0]=='+' || s[0]=='-')
     {
          j=1;
          if(s[0]=='-') k=1;
     }
     for(int i=s.size()-1;i>=j;i--)
     {
          switch(s[i])
          {
          case '0':x+=0*d;break;
          case '1':x+=1*d;break;
          case '2':x+=2*d;break;
          case '3':x+=3*d;break;
          case '4':x+=4*d;break;
          case '5':x+=5*d;break;
          case '6':x+=6*d;break;
          case '7':x+=7*d;break;
          case '8':x+=8*d;break;
          case '9':x+=9*d;break;
          }
          d*=10;
     }
     if(k==0)return x;
     return -x;
}
long tinh(cay t)
{
     long x;
     if(t)
     {
          if(t->s=="+") return tinh(t->left)+tinh(t->right);
          else if(t->s=="-") return tinh(t->left)-tinh(t->right);
          else if(t->s=="*") return tinh(t->left)*tinh(t->right);
          else if(t->s=="/") return tinh(t->left)/tinh(t->right);
          else return atol(t->s);
     }
     return 0;
}
void main()
{
     cay t;
     taocay(t);
     string s;
     cout<<"nhap bieu thuc toan hoc cua cac so nguyen duong:\n";
     getline(cin,s);
     t=setcay(s);
     cout<<"gia tri bieu thuc = "<<tinh(t)<<endl;
     system("pause");
}