1. 程式人生 > >第五章小結

第五章小結

else brush clas 節點 bit 公式 結構 color 使用方法

本章學的是二叉樹以及其具體操作。

我們學習了二叉樹的幾個性質,說實話好像數學公式一樣。性質如下

1)在二叉樹的第i層上至多有2i-1個結點。

2)深度為k的二叉樹上至多含2k - 1個結點(k≥1)。

3)對任何一棵二叉樹,若它含有n0個葉子結點、n2個度為2的結點,則必存在關系式:n0 = n2 + 1。

4)具有n個結點的完全二叉樹的深度為 (log2n) +1 。

5)對完全二叉樹,若從上至下、從左至右編號,則編號為 i 的結點,其左孩子編號必為2i,其右孩子編號必為2i+1;其雙親的編號必為i/2。

之後學了哈夫曼樹,感覺上課時學的很帶勁,但是課後左右還是挺吃力的。

上課的時候覺得樹的結構不算太難,畢竟有規律可循。但是真正用起來的時候發現並沒那麽簡單。拿下面這兩題為例吧

首先是實踐的第二題,深入虎穴。代碼如下。

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

typedef struct{
    int doors;//代表門的數量
    int *p; //p指向具體門的編號 ,把p看作整型數組 
}node;

int input(node *&a)
{
    int n,m,i,k,j;
    bool *vi; 
    cin>>n;
    a=new node[n+1];//為a數組申請空間
    vi=new
bool[n+1];//同上 for(i=1;i<=n;i++)//將vi數組初始化 { vi[i]=false; } for(i=1;i<=n;++i) { cin>>a[i].doors; a[i].p=new int[a[i].doors]; for(k=0;k<a[i].doors;++k)//new的空間下標為0到n-1 { cin>>a[i].p[k]; vi[a[i].p[k]]
=true; } } for(j=1;j<=n;j++) { if(!vi[j]) break; }return j; } int find(node*a,int root) {//從a數組root下標往下搜索 queue<int> q;//定義用於存放待訪問的門編號的隊列 int x; q.push(root);//根編號入隊 while(!q.empty())//隊列非空 { x=q.front(); q.pop(); for(int i=0;i<a[x].doors;++i) { q.push(a[x].p[i]); } } return x; } int main() { node *a;//定義一個動態的整型數組 int root; root=input(a);//找根 cout<<find(a,root)<<endl;//從根開始尋找 //cout<<root; return 0; }

這題是老師上課時帶著我們一起做的。回來自己試的時候發現幾個難點。首先第一個時動態申請的範圍。申請是從第0個開始,所以有的循環要從i=0開始,不然會出錯輸不出答案。然後是find函數中使用隊列,學到了用queue的頭文件的一些使用方法,以及層次遍歷的這種思想。

印象更深刻的是下面這道葉子節點的查找的題目。

代碼如下

#include<iostream>
#include<queue> 
using namespace std;
  
typedef struct
{
    char lchild;//左孩子的下標 
    char rchild;//右孩子的下標 
}node;

void levelOrderTraverse(node a[],int x); 
int createBiTree(node a[]);
 
int main()
{
     node a[10];
     int x;
     x=createBiTree(a);//帶回根節點
     levelOrderTraverse(a,x); 
}

int createBiTree(node a[])
{
    int n, i;
    char x,y;
    bool t[10]={false}; //用來查找根節點 
    cin>>n;

    for(i=0;i<n;i++)
	{
		cin>>x>>y;
    if(x!=‘-‘)//左節點 
    {
      a[i].lchild=x-‘0‘;//-‘0‘的作用是減去0的ASCII值,用於轉換 
      t[a[i].lchild]=true;
    }
    else a[i].lchild=-1;//無孩子 
        
    if(y!=‘-‘)//右節點處
    {
    a[i].rchild=y-‘0‘;//同上 
    t[a[i].rchild]=true;//
    }     
    else a[i].rchild=-1;//無孩子 
    }

    for(i=0;i<n;i++)
	{//找根節點 
    if(!t[i])
    return i;
    }
}
void levelOrderTraverse(node a[],int x)
{//層次遍歷 
    queue<int> q;
    int m;
    int leaves=0;//標記是第幾個葉子結點
    q.push(x);//入隊 
     
    while(!q.empty())
    {
        m=q.front();//取隊頭 
        q.pop();
        if(a[m].lchild==-1&&a[m].rchild==-1)
        {
            if(leaves)
            cout<<" ";
            cout<<m;
            ++leaves;
        }
        if(a[m].lchild!=-1)
        q.push(a[m].lchild);//左孩子入隊
        if(a[m].rchild!=-1)
        q.push(a[m].rchild); //右孩子入隊
    }
}

  這道題一開始沒什麽想法。特別時自上而下自左到右的輸出方式,是老師講了層次遍歷後才有了點想法。這道題中,請教了一些同學,發現了一個轉換字符數字的方法就是

a[i].lchild=x-0

這裏的-‘0’實際上是減去了0的ASCII碼,這樣很容易的實現了轉換。這題感覺和上一題很想,不過這題是自己敲出來的,感覺很不一樣。特別是用上了新學到的隊列處理,成就感還是很大的。

下一章的學習希望自己能跟緊老師的步伐吧,也要時刻提醒自己之前學習的知識可以用,就比如這次的隊列一樣。

第五章小結