二叉排序樹的建立


二叉排序樹

       二叉排序樹(Binary Sort Tree)又稱二叉查找樹(Binary Search Tree),亦稱二叉搜索樹。

性質

二叉排序樹或者是一棵空樹,是具有下列性質的二叉樹:
(1)若左子樹不空,則左子樹上所有結點的值均小於它的根結點的值;
(2)若右子樹不空,則右子樹上所有結點的值均大於它的根結點的值;
(3)左、右子樹也分別為二叉排序樹;
(4)沒有鍵值相等的節點。

可以看出,二叉查找樹是一個遞歸的數據結構,且對二叉查找樹進行中序遍歷,可以得到一個遞增的有序序列。

首先,我們來定義一下 BST 的結點結構體:

//樹的定義
typedef struct TreeNode
{
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
};

插入

//二叉排序樹的插入【遞歸】
int BST_insert(struct TreeNode *p,int k)
{
    //二叉樹中插入一個關鍵字為k的結點
    if(p == NULL)
    {
        p = (struct TreeNode*)malloc(sizeof(struct TreeNode));
        p ->val = k;
        p ->left = p ->right = NULL;
        return 1;  //返回1表示成功
    }
    //樹中存在相同的結點
    else if(k == p ->val)
        return 0;
    //插入到左子樹中
    else if(k < p ->val)
        return BST_insert(p ->left,k);
    //插入到右子樹中
    else
        return BST_insert(p ->right ,k);
}

注意,插入的新結點一定是某個葉結點。另外,插入操作既可以遞歸實現,也可以使用非遞歸(迭代)實現。通常來說非遞歸的效率會更高。 

/**
 * 非遞歸插入:將關鍵字k插入到二叉查找樹
 */
int BST_Insert_NonRecur(BSTree &T, int k)
{
    Node* pre = NULL;  // 記錄上一個結點
    Node* t = T;
    while(t != NULL)
    {
        pre = t;
        if(k < t->key)
            t = t->left;
        else if(k > t->key)
            t = t->right;
        else
            return 0;
    }
 
    Node* node = (Node*)malloc(sizeof(Node));
    node->key = k;
    node->left = NULL;
    node->right = NULL;
    node->parent = pre;
 
    if(pre == NULL)
        T = node;
    else
    {
        if(k < pre->key)
            pre->left = node;
        else
            pre->right = node;
    }
    return 1;
}

創建  

//二叉樹的構建
void BST_create(struct TreeNode *T,int *str,int n)
{
    //用關鍵字數組建立一個二叉排序樹
    T = NULL; //初始時為空樹
    int i = 0;
    //依次將每個元素插入
    while(i < n)
    {
        BST_insert(T,str[i]);
        i++;
    }
}

遍歷  

//【前序遍歷】
void preorder(struct TreeNode *T)
{
    if(T != NULL)
    {
        printf("%d\t",T ->val); //打印根結點
        inorder(T ->left);  //遞歸遍歷左子樹
        inorder(T ->right); //遞歸遍歷右子樹
    }
}
//【后序遍歷】
void inorder(struct TreeNode *T)
{
    if(T != NULL)
    {
        inorder(T ->left);  //遞歸遍歷左子樹
        inorder(T ->right); //遞歸遍歷右子樹
        printf("%d\t",T ->val); //打印根結點
    }
}
//【中序遍歷】
void postorder(struct TreeNode *T)
{
    if(T != NULL)
    {
        inorder(T ->left);  //遞歸遍歷左子樹
        printf("%d\t",T ->val); //打印根結點
        inorder(T ->right); //遞歸遍歷右子樹
    }
}

完整代碼

#include <stdio.h>
#include <stdlib.h>

//樹的定義
typedef struct TreeNode
{
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
};
struct TreeNode *T;
//二叉排序樹的插入
int BST_insert(struct TreeNode *p,int k)
{
    //二叉樹中插入一個關鍵字為k的結點
    if(p == NULL)
    {
        p = (struct TreeNode*)malloc(sizeof(struct TreeNode));
        p ->val = k;
        p ->left = p ->right = NULL;
        return 1;  //返回1表示成功
    }
    //樹中存在相同的結點
    else if(k == p->val)
        return 0;
    //插入到左子樹中
    else if(k < p ->val)
        return BST_insert(p ->left,k);
    //插入到右子樹中
    else
        return BST_insert(p ->right ,k);
}
//二叉樹的構建
void BST_create(struct TreeNode *T,int *str,int n)
{
    //用關鍵字數組建立一個二叉排序樹
	T = NULL;//初始時為空樹
    int i;
    //依次將每個元素插入
    for(i = 0;i < n;i++)
    {
        BST_insert(T,str[i]);
    }
}
//【前序遍歷】
void preorder(struct TreeNode *T)
{
    if(T != NULL)
    {
        printf("%d\t",T ->val); //打印根結點
        inorder(T ->left);  //遞歸遍歷左子樹
        inorder(T ->right); //遞歸遍歷右子樹
    }
}
//【中序遍歷】
void inorder(struct TreeNode *T)
{
    if(T != NULL)
    {
        inorder(T ->left);  //遞歸遍歷左子樹
        inorder(T ->right); //遞歸遍歷右子樹
        printf("%d\t",T ->val); //打印根結點
    }
}
//【后序遍歷】
void postorder(struct TreeNode *T)
{
    if(T != NULL)
    {
        inorder(T ->left);  //遞歸遍歷左子樹
        printf("%d\t",T ->val); //打印根結點
        inorder(T ->right); //遞歸遍歷右子樹
    }
}
int main()
{
    int length,str[] = {3,1,4,NULL,2};
    struct TreeNode *root;
    length = sizeof(str) / sizeof(str[0]);
    BST_create(root,str,length);
    printf("前序遍歷:");
    preorder(root);
    printf("\n中序遍歷:");
    inorder(root);
    printf("\n后序遍歷:");
    postorder(root);
    return 0;
}

問題

BST_insert(T,str[i]);每次調用時,傳進去的 T 為什么都是 NULL ?

該問題是:傳值出現問題,待有緣人解決!


下面給出新的思路:

以下程序均在VS下調試!

這位大哥在創建二叉樹時居然是一個節點一個節點寫入的,真的強![2]

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef struct node
{
    int nValue;
    struct node* pLeft;
    struct node* pRight;
}BiTree;

BiTree* CreateBiTree(void)
{
    BiTree* pRoot = NULL;

    //根
    pRoot = (BiTree*)malloc(sizeof(BiTree));
    if (NULL == pRoot)
    {
        printf("pRoot空間分配失敗!\n");
        exit(-1);
    }
    pRoot->nValue = 1;
    pRoot->pLeft = NULL;
    pRoot->pRight = NULL;

    //根的左
    pRoot->pLeft = (BiTree*)malloc(sizeof(BiTree));
    if (NULL == pRoot->pLeft)
    {
        printf("pRoot->pLeft空間分配失敗!\n");
        exit(-1);
    }
    pRoot->pLeft->nValue = 2;
    pRoot->pLeft->pLeft = NULL;
    pRoot->pLeft->pRight = NULL;

    //根的右
    pRoot->pRight = (BiTree*)malloc(sizeof(BiTree));
    if (NULL == pRoot->pRight)
    {
        printf("pRoot->pRight空間分配失敗!\n");
        exit(-1);
    }
    pRoot->pRight->nValue = 3;
    pRoot->pRight->pLeft = NULL;
    pRoot->pRight->pRight = NULL;

    //左的左
    pRoot->pLeft->pLeft = (BiTree*)malloc(sizeof(BiTree));
    if (NULL == pRoot->pLeft->pLeft)
    {
        printf("pRoot->pLeft->pLeft空間分配失敗!\n");
        exit(-1);
    }
    pRoot->pLeft->pLeft->nValue = 4;
    pRoot->pLeft->pLeft->pLeft = NULL;
    pRoot->pLeft->pLeft->pRight = NULL;

    //左的右
    pRoot->pLeft->pRight = (BiTree*)malloc(sizeof(BiTree));
    if (NULL == pRoot->pLeft->pRight)
    {
        printf("pRoot->pLeft->pRight空間分配失敗!\n");
        exit(-1);
    }
    pRoot->pLeft->pRight->nValue = 5;
    pRoot->pLeft->pRight->pLeft = NULL;
    pRoot->pLeft->pRight->pRight = NULL;

    //右的左
    pRoot->pRight->pLeft = (BiTree*)malloc(sizeof(BiTree));
    if (NULL == pRoot->pRight->pLeft)
    {
        printf("pRoot->pRight->pLeft空間分配失敗!\n");
        exit(-1);
    }
    pRoot->pRight->pLeft->nValue = 6;
    pRoot->pRight->pLeft->pLeft = NULL;
    pRoot->pRight->pLeft->pRight = NULL;

    return pRoot;
}

//遞歸創建二叉樹
void RecCreateBiTree(BiTree** ppRoot)
{
    int nNum;

    assert(ppRoot != NULL);

    //輸入節點的值
    scanf("%d", &nNum);

    //檢測是否是結束標志
    if (0 == nNum)
    {
        return;
    }

    *ppRoot = (BiTree*)malloc(sizeof(BiTree));
    if (NULL == *ppRoot)
    {
        printf("*ppRoot空間分配失敗!");
        exit(-1);
    }
    (*ppRoot)->nValue = nNum;
    (*ppRoot)->pLeft = NULL;
    (*ppRoot)->pRight = NULL;

    //處理當前節點的左和右
    RecCreateBiTree(&(*ppRoot)->pLeft);
    RecCreateBiTree(&(*ppRoot)->pRight);
}

//前序遍歷
void PreOrderTraversal(BiTree* pRoot)
{
    if (NULL == pRoot)
    {
        return;
    }

    printf("%d ", pRoot->nValue);
    PreOrderTraversal(pRoot->pLeft);
    PreOrderTraversal(pRoot->pRight);
}

//中序遍歷
void MidOrderTraversal(BiTree* pRoot)
{
    if (NULL == pRoot)
    {
        return;
    }

    MidOrderTraversal(pRoot->pLeft);
    printf("%d ", pRoot->nValue);
    MidOrderTraversal(pRoot->pRight);
}

//后序遍歷
void LastOrderTraversal(BiTree* pRoot)
{
    if (NULL == pRoot)
    {
        return;
    }

    LastOrderTraversal(pRoot->pLeft);
    LastOrderTraversal(pRoot->pRight);
    printf("%d ", pRoot->nValue);
}

int main(void)
{
    printf("新建二叉樹:");
    BiTree* pRoot = CreateBiTree();
    printf("前序遍歷:");
    PreOrderTraversal(pRoot);
    printf("\n");
    printf("中序遍歷:");
    MidOrderTraversal(pRoot);
    printf("\n");
    printf("后序遍歷:");
    LastOrderTraversal(pRoot);

    system("pause");
    return 0;
}

下面的這個參考知乎一位老哥[1],稍微修改一下:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

struct Node
{
	int data;
	struct Node* pleft;
	struct Node* pright;
}Node;

//參數聲明
struct Node* createnode(int value);
struct Node* addnode(int value, struct Node* pnode);
void ppreorder(struct TreeNode* T);
void pinorder(struct TreeNode* T);
void ppostorder(struct TreeNode* T);
void listnodes(struct Node* pnode);
int Treeheight(struct Node* pnode);

struct Node* createnode(int value)
{
	struct Node* pnode = (struct Node*)malloc(sizeof(struct Node));
	pnode->data = value;
	pnode->pleft = pnode->pright = NULL;
	return pnode;
}

struct Node* addnode(int value, struct Node* pnode)
{
	if (pnode == NULL)
		return createnode(value);

	if (value == pnode->data)
	{
		return pnode;
	}

	if (value < pnode->data)
	{
		if (pnode->pleft == NULL)
		{
			pnode->pleft = createnode(value);
			return pnode->pleft;
		}
		else
		{
			return addnode(value, pnode->pleft);
		}
	}
	else
	{
		if (pnode->pright == NULL)
		{
			pnode->pright = createnode(value);
			return pnode->pright;
		}
		else
		{
			return addnode(value, pnode->pright);
		}

	}
}

//【前序遍歷】
void ppreorder(struct Node* pnode)
{
	if (pnode != NULL)
	{
		printf("%d\t", pnode->data); //打印根結點
		pinorder(pnode->pleft);  //遞歸遍歷左子樹
		pinorder(pnode->pright); //遞歸遍歷右子樹
	}
}
//【中序遍歷】
void pinorder(struct Node* pnode)
{
	if (pnode != NULL)
	{
		pinorder(pnode->pleft);  //遞歸遍歷左子樹
		pinorder(pnode->pright); //遞歸遍歷右子樹
		printf("%d\t", pnode->data); //打印根結點
	}
}
//【后序遍歷】
void ppostorder(struct Node* pnode)
{
	if (pnode != NULL)
	{
		pinorder(pnode->pleft);  //遞歸遍歷左子樹
		printf("%d\t", pnode->data); //打印根結點
		pinorder(pnode->pright); //遞歸遍歷右子樹
	}
}

void listnodes(struct Node* pnode)
{
	if (pnode != NULL)
	{
		listnodes(pnode->pleft);
		printf("%d\n", pnode->data);
		listnodes(pnode->pright);
	}
}

int Treeheight(struct Node* pnode)
{
	int LD, RD;
	if (pnode == NULL)
	{
		return 0;
	}
	else
	{
		LD = Treeheight(pnode->pleft);
		RD = Treeheight(pnode->pright);
		return (LD >= RD ? LD : RD) + 1;
	}
}

int main(void)
{
	int i;
	struct Node* proot = NULL;
	int length, str[] = { 3,1,4,NULL,2 };
	length = sizeof(str) / sizeof(str[0]);

	for (i = 0; i < length; i++)
	{
		if (proot == NULL)
		{
			proot = createnode(str[i]);
		}
		else
		{
			addnode(str[i], proot);
		}
	}
	printf("新建二叉樹:");
	listnodes(proot);
	printf("\nThe height of tree is %d!", Treeheight(proot));
	printf("\n前序遍歷:");
	ppreorder(proot);
	printf("\n中序遍歷:");
	pinorder(proot);
	printf("\n后序遍歷:");
	ppostorder(proot);
	return 0;
}

參考

1、二叉樹的建立與遍歷(C語言實現)

2、創建二叉樹


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM