1. 程式人生 > >二叉排序樹C語言實現

二叉排序樹C語言實現

目錄


說明


  • 用C語言實現資料結構,二叉排序樹,可動態插入二叉樹結點,遍歷二叉樹結點到一個連結串列。

程式碼


#include<stdio.h>
#include<stdlib.h>
typedef int Tp;

//連結串列
typedef struct node
{
    Tp data;
    struct node * ltree, *rtree;

}Node,*Tree;

//排序二叉樹
typedef struct listnode { Tp data; struct listnode * nextnode; }lNode,*List; //往排序二叉樹送入值 bool insertTree(Tree * T, const Tp data) { Node * pnode = (Node*)malloc(sizeof(Node)); //printf("pnode add: %p\n", pnode); pnode->data = data; pnode->ltree = NULL; pnode->rtree = NULL; if
(!(*T)) { *T = pnode; return true; } else { if (pnode->data < (*T)->data )//若小於根節點值 { if ((*T)->ltree)//若左子樹不為空,繼續遞迴 { Node pnodecpy = *pnode;//由於要遞迴,防止記憶體洩漏,這裡需要將申請的記憶體堆轉移出來,然後清空這個堆記憶體 free
(pnode); pnode = NULL; insertTree(&((*T)->ltree), pnodecpy.data); } else//若左子樹為空,直接賦值 { (*T)->ltree = pnode; return true; } } else if (pnode->data > (*T)->data)//若大於根節點值 { if ((*T)->rtree)//若右子樹不為空,繼續遞迴 { Node pnodecpy = *pnode;//由於要遞迴,防止記憶體洩漏,這裡需要將申請的記憶體堆轉移出來,然後清空這個堆記憶體 free(pnode); pnode = NULL; insertTree(&((*T)->rtree), pnodecpy.data); } else//若右子樹為空,直接賦值 { (*T)->rtree = pnode; return true; } } else { return true; } } } //在連結串列尾部插入新元素函式 bool inserList(List *list, Tp data) { lNode *datanode = (lNode*)malloc(sizeof(lNode)); datanode->data = data; datanode->nextnode = NULL; if (!(*list))//若連結串列為空 { *list = datanode; return true; } else//若連結串列不為空 { if ((*list)->nextnode == NULL)//若插入為本連結串列的第二個元素 { (*list)->nextnode = datanode; return true; } else//若插入為本連結串列的第3個元素及以上,迭代至最後一個元素 { lNode nodecpy = *datanode; free(datanode); datanode = NULL; return inserList(&((*list)->nextnode), nodecpy.data); } } } //中序遍歷二叉樹函式,將遍歷結果儲存在一個連結串列裡 bool inorderTraversal(Tree t, List *l) { if (!t) { //printf("樹為空"); return false; } else { if (t->ltree==NULL&&t->rtree==NULL) { printf(" %d ", t->data); return inserList(l, t->data); } else { inorderTraversal(t->ltree, l);//訪問左子樹 printf(" %d ", t->data); bool i = inserList(l, t->data);//訪問根節點 inorderTraversal(t->rtree, l);//訪問右子樹 return true; } } } int main() { Tree t = NULL; List l = NULL; //連結串列初始化 bool b = false; b = insertTree(&t, 44); b = insertTree(&t, 55); b = insertTree(&t, 33); b = insertTree(&t, 20); b = insertTree(&t, 45); b = insertTree(&t, 37); printf("樹的地:%p\n左子樹地址:%p\n右子樹地址:%p\n", t, t->ltree, t->rtree); printf("\n中序遍歷結果(從小到大):"); b = inorderTraversal(t, &l); printf("\n中序遍歷結果(儲存在連結串列):"); printf("連結串列的頭節點地址: %p\n", l); system("pause"); return 0; }

執行結果
這裡寫圖片描述

一些思考


  • 在遞迴前,若是涉及在堆空間上動態開闢記憶體(如本文程式碼inserList() insertTree() 函式的malloc操作),為了防止遞迴的過程中不斷開闢新堆空間而造成的浪費和風險,須在遞迴前將申請的記憶體中的變數儲存下來(棧),再去遞迴。

  • 從無到有生成一個動態的資料的函式,傳入引數須傳入二級指標,以實現malloc,因為malloc 須賦值返回給一個指標變數,即修改一個指標變數,眾說周知,修改一個指標變數需傳入指標的指標,即二級指標來修改。

  • 根據上一條的結論,若函式須讀,可僅僅傳入一個值(值傳遞),若函式須讀寫,可以考慮傳入一個指標(指標傳遞),若寫一個值,傳入指標,若寫一個指標(地址,原或為NULL),傳入一個二級指標,以此類推。