赞
踩
今天来给大家讲解一下二叉排序树C语言代码实现
-
-
- typedef int ElemType; // 自定义数据元素为整数。
-
- // 二叉树的数据结构。
- typedef struct BSTNode
- {
- ElemType data; // 存放结点的数据元素。
- struct BSTNode* lchild; // 指向左子结点地址的指针。
- struct BSTNode* rchild; // 指向右子结点地址的指针。
- }BSTNode, * BSTree;
- ///
-
- // 在树TT中插入关键字为ee的新结点(递归实现),返回值:0-树中已存在关键字为ee的结点;1-成功。
- int Insert(BSTree* TT, ElemType* ee);
- // 在树TT中插入关键字为ee的新结点(非递归实现),返回值:0-树中已存在关键字为ee的结点;1-成功。
- int Insert1(BSTree* TT, ElemType* ee);
-
- // 用数组arr中的序列构建二叉排序树TT。
- // 以下两种写法都可以。
- //void CreateBST(BSTree *TT,int arr[],int len);
- void CreateBST(BSTree* TT, int* arr, int len);
-
- // 在树TT中查找值为ee的结点(递归实现),成功返回结点的地址,失败返回NULL。
- BSTNode* Find(BSTree TT, ElemType* ee);
- // 在树TT中查找值为ee的结点(非递归实现),成功返回结点的地址,失败返回NULL。
- BSTNode* Find1(BSTree TT, ElemType* ee);
-
- // 在树TT中删除值为ee的结点,成功返回0,结点不存在返回1。
- int Delete(BSTree* TT, ElemType* ee);
-
- // 求二叉树的高度。
- int TreeDepth(BSTree TT);
-
- // 访问结点元素。
- void visit(BSTNode* pp);
-
- // 采用递归的方法对二叉树的先序遍历。
- void PreOrder(BSTree TT);
-
- // 采用递归的方法对二叉树的中序遍历。
- void InOrder(BSTree TT);
-
- // 采用递归的方法对二叉树的后序遍历。
- void PostOrder(BSTree TT);
-
- int main()
- {
- BSTree TT = 0; // 声明树指针变量。
-
- ElemType arr[] = { 50,66,60,26,21,30,70,68 };
-
- /*
- // 用数组arr中的序列构建二叉排序树TT。
- // 构建的二叉排序树将如下:
- 50
- / \
- 26 66
- / \ / \
- 21 30 60 70
- /
- 68
- */
- CreateBST(&TT, arr, sizeof(arr) / sizeof(ElemType));
-
- ElemType ee;
-
- // 在树TT中查找值为ee的结点,成功返回结点的地址,失败返回NULL。
- ee = 30;
- BSTNode* ss = Find(TT, &ee);
- if (ss != NULL) printf("查找成功,结点的地址是%p,值是%d。\n", ss, ss->data);
- else printf("查找失败。\n");
-
- // 二叉树的中序遍历。
- printf("中序遍历结果1:"); InOrder(TT); printf("\n");
-
- // 在树TT中删除值为ee的结点,成功返回0,结点不存在返回1。
- ee = 50;
- printf("从树中删除值为ee的结点,Delete()的返回值是%d。\n", Delete(&TT, &ee));
-
- // 二叉树的中序遍历。
- printf("中序遍历结果2:"); InOrder(TT); printf("\n");
-
- return 0;
- }
-
- // 二叉树的先序遍历。
- void PreOrder(BSTree TT)
- {
- if (TT == NULL) return;
-
- visit(TT); // 访问子树TT的根结点。
- PreOrder(TT->lchild); // 遍历左子树。
- PreOrder(TT->rchild); // 遍历右子树。
- }
-
- // 二叉树的中序遍历。
- void InOrder(BSTree TT)
- {
- if (TT == NULL) return;
-
- InOrder(TT->lchild); // 遍历左子树。
- visit(TT); // 访问子树TT的根结点。
- InOrder(TT->rchild); // 遍历右子树。
- }
-
- // 二叉树的后序遍历。
- void PostOrder(BSTree TT)
- {
- if (TT == NULL) return;
-
- PostOrder(TT->lchild); // 遍历左子树。
- PostOrder(TT->rchild); // 遍历右子树。
- visit(TT); // 访问子树TT的根结点。
- }
-
- // 求二叉树的高度。
- int TreeDepth(BSTree TT)
- {
- if (TT == NULL) return 0;
-
- int ll = TreeDepth(TT->lchild); // 求左子树的高度。
-
- int rr = TreeDepth(TT->rchild); // 求右子树的高度。
-
- return ll > rr ? ll + 1 : rr + 1; // 取左、右子树的较大者再加上根结点的高度。
- }
-
- // 访问结点元素。
- void visit(BSTNode* pp)
- {
- printf("%d ", pp->data); // 访问结点元素就是把值输出来,意思一下就行了。
- }
-
- // 在树TT中插入关键字为ee的新结点(递归实现),返回值:0-树中已存在关键字为ee的结点;1-成功。
- int Insert(BSTree* TT, ElemType* ee)
- {
- // 如果当前子树为空,创建子树的根结点。
- if ((*TT) == NULL)
- {
- (*TT) = (BSTree)malloc(sizeof(BSTNode));
- memcpy(&(*TT)->data, ee, sizeof(ElemType)); // 考虑数据元素ee为结构体的情况,采用memcpy而不是直接赋值。
- (*TT)->lchild = (*TT)->rchild = NULL; // 当前子树的左右孩子指针置空。
- return 1; // 返回成功。
- }
-
- if (*ee == (*TT)->data) return 0; // 如果ee已存在,返回失败。
-
- if (*ee < (*TT)->data) Insert(&(*TT)->lchild, ee); // 递归向左插入。
- else Insert(&(*TT)->rchild, ee); // 递归向右插入。
- }
-
- // 在树TT中插入关键字为ee的新结点(非递归实现),返回值:0-树中已存在关键字为ee的结点;1-成功。
- int Insert1(BSTree* TT, ElemType* ee)
- {
- // 如果树为空,创建树的根结点。
- if ((*TT) == NULL)
- {
- (*TT) = (BSTree)malloc(sizeof(BSTNode));
- memcpy(&(*TT)->data, ee, sizeof(ElemType)); // 考虑数据元素ee为结构体的情况,采用memcpy而不是直接赋值。
- (*TT)->lchild = (*TT)->rchild = NULL; // 树的左右孩子指针置空。
- return 1; // 返回成功。
- }
-
- BSTNode* pss = NULL; // 记录双亲结点的地址。
- BSTNode* ss = (*TT); // 用于查找的临时指针。
- int rl = 0; // 记录ss是双亲结点的左子树还是右子树,0-左子树;1-右子树。
-
- while (ss != NULL)
- {
- if (*ee == ss->data) return 0; // 如果ee已存在,返回失败。
-
- pss = ss; // 记录双亲结点的地址。
- if (*ee < ss->data) { ss = ss->lchild; rl = 0; } // 继续向左走。
- else { ss = ss->rchild; rl = 1; } // 继续向右走。
- }
-
- // 分配新结点。
- ss = (BSTree)malloc(sizeof(BSTNode));
- memcpy(&ss->data, ee, sizeof(ElemType)); // 考虑数据元素ee为结构体的情况,采用memcpy而不是直接赋值。
- ss->lchild = ss->rchild = NULL; // 当前子树的左右孩子指针置空。
-
- // 让双亲结点的左或右指针指向新分配的结点。
- if (rl == 0) pss->lchild = ss;
- else pss->rchild = ss;
-
- return 1; // 返回成功。
- }
-
- // 用数组arr中的序列构建二叉排序树TT。
- // 以下两种写法都可以。
- //void CreateBST(BSTree *TT,int arr[],int len)
- void CreateBST(BSTree* TT, int* arr, int len)
- {
- (*TT) = NULL;
-
- int ii = 0;
- for (ii = 0; ii < len; ii++)
- {
- Insert(TT, &arr[ii]); // 把数组中的元素逐个插入树中。
- // Insert1(TT,&arr[ii]); // 把数组中的元素逐个插入树中。
- }
- }
-
- // 在树TT中查找值为ee的结点(递归实现),成功返回结点的地址,失败返回NULL。
- BSTNode* Find(BSTree TT, ElemType* ee)
- {
- if (TT == NULL) return NULL; // 查找失败。
-
- if (*ee == TT->data) return TT; // 查找成功。
-
- if (*ee < TT->data) return Find(TT->lchild, ee); // 递归向左查找。
- else return Find(TT->rchild, ee); // 递归向右查找。
- }
-
- // 在树TT中查找值为ee的结点(非递归实现),成功返回结点的地址,失败返回NULL。
- BSTNode* Find1(BSTree TT, ElemType* ee)
- {
- BSTNode* ss = TT; // 用于查找的临时指针,也可以直接用TT。
-
- while (ss != NULL)
- {
- if (*ee == ss->data) return ss; // 成功找到。
-
- if (*ee < ss->data) ss = ss->lchild; // 继续向左走。
- else ss = ss->rchild; // 继续向右走。
- }
-
- return NULL;
-
- /*
- // 以下代码更精简,可以取代以上的代码。
- while ( (TT!=NULL) && (*ee!=TT->data) )
- {
- if (*ee<TT->data) TT=TT->lchild; // 继续向左走。
- else TT=TT->rchild; // 继续向右走。
- }
-
- return TT;
- */
- }
-
- // 在树TT中删除值为ee的结点,成功返回0,结点不存在返回1。
- int Delete(BSTree* TT, ElemType* ee)
- {
- if ((*TT) == NULL) return 1; // 树为空,返回1。
-
- // 1)如果树只有根结点,并且待删除的结点就是根结点。
- if (((*TT)->data == *ee) && ((*TT)->lchild == NULL) && ((*TT)->rchild == NULL))
- {
- free(*TT); (*TT) = 0; return 0;
- }
-
- BSTNode* pss = NULL; // 记录双亲结点的地址。
- BSTNode* ss = (*TT); // 用于查找的临时指针。
- int rl = 0; // 记录ss是双亲结点的左子树还是右子树,0-左子树;1-右子树。
-
- // 查找待删除的结点。
- while (ss != NULL)
- {
- if (*ee == ss->data) break; // 成功找到。
-
- pss = ss; // 记录双亲结点的地址。
- if (*ee < ss->data) { ss = ss->lchild; rl = 0; } // 继续向左走。
- else { ss = ss->rchild; rl = 1; } // 继续向右走。
- }
-
- // 结点不存在,返回1。
- if (ss == NULL) return 1;
-
- // 2)如果待删除的结点ss是叶结点,直接删除,不会破坏二叉排序树的性质。
- if ((ss->lchild == NULL) && (ss->rchild == NULL))
- {
- free(ss); // 释放结点。
-
- // 修改双亲结点pss的左或右指针指向NULL。
- if (rl == 0) pss->lchild = NULL;
- else pss->rchild = NULL;
-
- return 0; // 返回成功。
- }
-
- // 3)如果待删除的结点ss只有左子树或右子树,则让子树代替自己。
- if ((ss->lchild == NULL) || (ss->rchild == NULL))
- {
- if (ss->lchild != NULL) // 有左子树。
- {
- // 修改双亲结点pss的左或右指针指向ss的左子树。
- if (rl == 0) pss->lchild = ss->lchild;
- else pss->rchild = ss->lchild;
- }
- else // 有右子树。
- {
- // 修改双亲结点pss的左或右指针指向ss的右子树。
- if (rl == 0) pss->lchild = ss->rchild;
- else pss->rchild = ss->rchild;
- }
-
- return 0; // 返回成功。
- }
-
- // 4)如果待删除的结点ss有左子树和右子树,让左子树最右侧的结点代替自己,然后再删除左子树最右侧的结点。
- // 也可以让右子树最左侧的结点代替自己,然后删除右子树最左侧的结点。
- BSTNode* pss1 = ss; // 记录双亲结点的地址。
- BSTNode* ss1 = ss->lchild; // 用于查找的临时指针。
- int rl1 = 0; // 记录ss1是双亲结点的左子树还是右子树,0-左子树;1-右子树。
-
- // 左子树向右走到尽头。
- while (ss1->rchild != NULL)
- {
- rl1 = 1; pss1 = ss1; ss1 = ss1->rchild;
- }
-
- // 把左子树最右侧的结点值复制到结点ss中。
-
-
- // 左子树最右侧的结点ss1必定无右子树。
- // 修改双亲结点pss1的左或右指针指向ss1的左子树,ss1的左子树可以为空。
- if (rl1 == 0) pss1->lchild = ss1->lchild;
- else pss1->rchild = ss1->lchild;
-
- free(ss1); // 释放ss1。
-
- return 0;
- }
-
-
- //删除写法二:
- //直接返回删除后的树
- BSTree Delete2(BSTree TT, ElemType ee)
- {
- BSTree f, p;
- //f指针记录待删除结点的双亲结点
- //p指针用来记录待删除结点
- f = NULL;
- p = TT;
- while (p)
- {
- if (p->data = ee) break;
- f = p;
- if (p->data > ee) p = p->lchild;
- else p = p->rchild;
- }
-
- //第一种情况p为NULL,即是没有待删除结点
- if (p == NULL) return TT;
-
- //分为两种情况,待删除结点有左子树和无左子树
- if (p->lchild == NULL) //无左子树
- {
- //对双亲结点进行三种讨论
-
- //第一种如果双亲结点是空
- if (f == NULL) TT = p->rchild;
-
- //第二种p是f的左孩子
- else if (f->lchild == p) f->lchild = p->rchild;
-
- //第三种p是f的右孩子
-
- else f->rchild = p->rchild;
-
- free(p);
-
- }
-
- //找到以p为根节点左子树的最右边
-
- else
- {
- //m是n的双亲结点
-
- //m为p结点,n为p结点的左孩子
- BSTree m = p, n = p->lchild;
-
- //找到以p为根节点左子树的最右边
- while (n->rchild)
- {
- m = n;
- n = n->rchild;
- }
-
- //为两种情况,以n为根节点的树有无右子树
-
- if (p == m) m->lchild = n->lchild;
-
- else m->rchild = n->lchild;
-
- p->data = n->data;
-
- free(n);
-
-
-
- }
- return TT;
-
-
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。