二叉排序树的建立
二叉排序树
二叉排序树(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; }
参考
2、创建二叉树