二叉排序樹C語言實現
阿新 • • 發佈:2018-12-19
目錄
說明
- 用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),傳入一個二級指標,以此類推。