程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 一步一步寫算法(之排序二叉樹)

一步一步寫算法(之排序二叉樹)

編輯:關於C語言

 

【 聲明:版權所有,歡迎轉載,請勿用於商業用途。  聯系信箱:feixiaoxing @163.com】

 

 

 

 

    前面我們講過雙向鏈表的數據結構。每一個循環節點有兩個指針,一個指向前面一個節點,一個指向後繼節點,這樣所有的節點像一顆顆珍珠一樣被一根線穿在了一起。然而今天我們討論的數據結構卻有一點不同,它有三個節點。它是這樣定義的:

 

 

typedef struct _TREE_NODE 

    int data; 

    struct _TREE_NODE* parent; 

    struct _TREE_NODE* left_child; 

    struct _TREE_NODE* right_child; 

}TREE_NODE; 

typedef struct _TREE_NODE

{

       int data;

       struct _TREE_NODE* parent;

       struct _TREE_NODE* left_child;

       struct _TREE_NODE* right_child;

}TREE_NODE;    根據上面的數據結構,我們看到每一個數據節點都有三個指針,分別是:指向父母的指針,指向左孩子的指針,指向右孩子的指針。每一個節點都是通過指針相互連接的。相連指針的關系都是父子關系。那麼排序二叉樹又是什麼意思呢?其實很簡單,只要在二叉樹的基本定義上增加兩個基本條件就可以了:(1)所有左子樹的節點數值都小於此節點的數值;(2)所有右節點的數值都大於此節點的數值。

 

    既然看到了節點的定義,那麼我們並可以得到,只要按照一定的順序遍歷,可以把二叉樹中的節點按照某一個順序打印出來。那麼,節點的創建、查找、遍歷是怎麼進行的呢,二叉樹的高度應該怎麼計算呢?我們一一道來。

 

    1)創建二叉樹節點

 

 

TREE_NODE* create_tree_node(int data) 

    TREE_NODE* pTreeNode = NULL; 

    pTreeNode = (TREE_NODE*)malloc(sizeof(TREE_NODE)); 

    assert(NULL != pTreeNode); 

 

    memset(pTreeNode, 0, sizeof(TREE_NODE)); 

    pTreeNode->data = data; 

    return pTreeNode; 

TREE_NODE* create_tree_node(int data)

{

       TREE_NODE* pTreeNode = NULL;

       pTreeNode = (TREE_NODE*)malloc(sizeof(TREE_NODE));

       assert(NULL != pTreeNode);

 

       memset(pTreeNode, 0, sizeof(TREE_NODE));

       pTreeNode->data = data;

       return pTreeNode;

}    分析:我們看到,二叉樹節點的創建和我們看到的鏈表節點、堆棧節點創建沒有什麼本質的區別。首先需要為節點創建內存,然後對內存進行初始化處理。最後將輸入參數data輸入到tree_node當中即可。

 

 

 

 

    2)數據的查找

 

 

TREE_NODE* find_data_in_tree_node(const TREE_NODE* pTreeNode, int data) 

    if(NULL == pTreeNode) 

        return NULL; 

 

    if(data == pTreeNode->data) 

        return (TREE_NODE*)pTreeNode; 

    else if(data < pTreeNode->data) 

        return find_data_in_tree_node(pTreeNode->left_child, data); 

    else 

        return find_data_in_tree_node(pTreeNode->right_child, data); 

TREE_NODE* find_data_in_tree_node(const TREE_NODE* pTreeNode, int data)

{

       if(NULL == pTreeNode)

              return NULL;

 

       if(data == pTreeNode->data)

              return (TREE_NODE*)pTreeNode;

       else if(data < pTreeNode->data)

              return find_data_in_tree_node(pTreeNode->left_child, data);

       else

              return find_data_in_tree_node(pTreeNode->right_child, data);

}    分析:我們的查找是按照遞歸迭代進行的。因為整個二叉樹是一個排序二叉樹,所以我們的數據只需要和每一個節點依次比較就可以了,如果數值比節點數據小,那麼向左繼續遍歷;反之向右繼續遍歷。如果遍歷下去遇到了NULL指針,只能說明當前的數據在二叉樹中還不存在。

 

 

 

 

    3)數據統計

 

 

int count_node_number_in_tree(const TREE_NODE* pTreeNode) 

    if(NULL == pTreeNode) 

        return 0; 

 

    return 1 + count_node_number_in_tree(pTreeNode->left_child) 

        + count_node_number_in_tree(pTreeNode->right_child); 

int count_node_number_in_tree(const TREE_NODE* pTreeNode)

{

       if(NULL == pTreeNode)

              return 0;

 

       return 1 + count_node_number_in_tree(pTreeNode->left_child)

              + count_node_number_in_tree(pTreeNode->right_child);

}    分析:和上面查找數據一樣,統計的工作也比較簡單。如果是節點指針,那麼直接返回0即可,否則就需要分別統計左節點樹的節點個數、右節點樹的節點個數,這樣所有的節點總數加起來就可以了。

 

 

 

 

    4)按照從小到大的順序打印節點的數據

 

 

void print_all_node_data(const TREE_NODE* pTreeNode) 

    if(pTreeNode){ 

        print_all_node_data(pTreeNode->left_child); 

        printf("%d\n", pTreeNode->data); 

        print_all_node_data(pTreeNode->right_child); 

    } 

void print_all_node_data(const TREE_NODE* pTreeNode)

{

       if(pTreeNode){

              print_all_node_data(pTreeNode->left_child);

              printf("%d\n", pTreeNode->data);

              print_all_node_data(pTreeNode->right_child);

       }

}    分析:因為二叉樹本身的特殊性,按順序打印二叉樹的函數本身也比較簡單。首先打印左子樹的節點,然後打印本節點的數值,最後打印右子樹節點的數值,這樣所有節點的數值就都可以打印出來了。

 

 

 

 

    5)統計樹的高度

 

 

int calculate_height_of_tree(const TREE_NODE* pTreeNode)  

    int left, right; 

    if(NULL == pTreeNode) 

        return 0; 

 

    left = calculate_height_of_tree(pTreeNode->left_child); 

    right = calculate_height_of_tree(pTreeNode->right_child); 

    return (left > right) ? (left + 1) : (right + 1); 

int calculate_height_of_tree(const TREE_NODE* pTreeNode)

{

       int left, right;

       if(NULL == pTreeNode)

              return 0;

 

       left = calculate_height_of_tree(pTreeNode->left_child);

       right = calculate_height_of_tree(pTreeNode->right_child);

       return (left > right) ? (left + 1) : (right + 1);

}    分析:樹的高度其實是指所有葉子節點中,從根節點到葉子節點的最大高度可以達到多少。當然,程序中表示得已經很明白了,如果節點為空,那麼很遺憾,節點的高度為0;反之如果左子樹的高度大於右子樹的高度,那麼整個二叉樹的節點高度就是左子樹的高度加上1;如果右子樹的高度大於左子樹的高度,那麼整個二叉樹的高度就是右子樹的高度加上1。計算樹的高度在我們設計平衡二叉樹的時候非常有用,特別是測試的時候,希望大家多多理解,熟練掌握。

 

 

 

 

總結:

 

    1)二叉樹是所有樹的基礎,後續的平衡二叉樹、線性二叉樹、紅黑樹、復合二叉樹、b樹、b+樹都以此為基礎,希望大家好好學習;

 

    2)二叉樹很多的操作是和堆棧緊密聯系在一起的,如果大家暫時理解不了遞歸,可以用循環或者堆棧代替;

 

    3)實踐出真知,大家可以自己對排序二叉樹的代碼多多練習。不瞞大家說,我個人寫平衡二叉樹不下20多遍,即使這樣也不能保證每次都正確;即使這樣,我每次寫代碼的都有不同的感覺。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved