题目:二叉排序树与平衡二叉树的实现
【问题描述】
设计并实现一个算法,分别用二叉链表和顺序表,实现对二叉排序树和平衡二叉树的的
操作。
【需求分析】
(
1
) 从磁盘文件 L.txt 中读入一组整型数据。
(
2
) 将读出的数据建成二叉排序树。
(
3
) 输入该二叉排序树的根结点,输出中序遍历结果。
(
4
) 输入二叉排序树的根结点,计算该二叉排序树的平均查找长度并输出。
(
5
) 输入要删除的数据,定位到该结点,并删除。
(
6
) 输入删除结点后的二叉排序树根结点,输出该二叉排序树的中序遍历结果。
(
7
) 读入一组数生成一棵平衡的二叉排序树,若插入或删除一个元素后,该二叉排
序树不平衡,则将它转化为平衡的二叉排序树。
(
8
) 输入平衡的二叉排序树的根结点,计算平衡的二叉树的平均查找长度并输出。
(
9
) 读入一组数存入顺序表中,生成一颗二叉排序树。、
(
10
) 输入该二叉排序树的根结点,输出中序遍历结果。
(
11
) 输入该二叉排序树的根结点,计算该二叉排序树的平均查找长度并输出。
(
12
) 输入要删除的数据,定位到该结点,并删除。
(
13
) 输入删除结点后的二叉排序树根结点,输出该二叉排序树的中序遍历结果。
【算法设计和实现】
主要函数
{
BSTNode
* createNode(
int
data
);
//创建一新结点
BSTNode
* insertBST(
BSTNode
*
root
,
int
data
);
//插入一个结点到二叉排序树
void
inorderTraversal(
BSTNode
*
root
);
//中序遍历二叉排序树
float
averageSearchLenth(
BSTNode
*
root
,
int
level
);
//计算二叉排序树的平均查找长度
BSTNode
* deleteNode(
BSTNode
*
root
,
int
data
);
//在二叉排序树中查找并删除指定元素
//平衡二叉树的操作
int
getHeight(
AVLNode
*
node
);
//计算树的高度
int
getmax(
int
a
,
int
b
);
//比较两者获取最大值
AVLNode
* createAVLNode(
int
data
);
//创建一个平衡二叉树结点
AVLNode
* insertAVL(
AVLNode
*
root
,
int
data
);
//插入一个结点到平衡二叉树
void
inorderTraversalAVL(
AVLNode
*
root
);
//中序遍历平衡二叉树
float
averageSearchLengthAVL(
AVLNode
*
root
,
int
level
);
//计算平衡二叉树的平均查找长度
AVLNode
* deleteNodeAVL(
AVLNode
*
root
,
int
data
);
//删除平衡二叉树内指定的元素
AVLNode
* rotateRight(
AVLNode
*
tree
);
//右旋转
AVLNode
* rotateLeft(
AVLNode
*
tree
);
//左旋转
AVLNode
* rotateRight_Left(
AVLNode
*
tree
);
//先右旋,再左旋
AVLNode
* rotateLeft_Right(
AVLNode
*
tree
);
//先左旋,再右旋
int
getBalanceFactor(
AVLNode
*
node
);
//获取平衡因子
//顺序表构建二叉排序树
void
insertSeqList(
SeqList
*
list
,
BSTNode
*
node
);
//在顺序表中插入一个结点
BSTNode
* buildBSTFromSeqList(
SeqList
*
List
);
//根据顺序表构建二叉排序树
}
存储结构
{
//二叉排序树的结点结构
typedef struct
BSTNode
{
int
data;
//结点存储的数据
struct
BSTNode
* left;
//左孩子指针
struct
BSTNode
* right;
//右孩子指针
}
BSTNode
;
//平衡二叉树的结点结构
typedef struct
AVLNode
{
int
data;
//结点存储的数据
int
height;
//结点的高度
struct
AVLNode
* left;
//左孩子指针
struct
AVLNode
* right;
//右孩子指针
}
AVLNode
;
//顺序表结构体
typedef struct
{
BSTNode
* data[
MAX_SIZE
];
//顺序表数组指针
int
length;
//顺序表长度
}
SeqList
;
}
源程序代码:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#define MAX_SIZE 100
//二叉排序树的结点结构
typedef struct BSTNode {
int data;//结点存储的数据
struct BSTNode* left;//左孩子指针
struct BSTNode* right;//右孩子指针
}BSTNode;
//平衡二叉树的结点结构
typedef struct AVLNode {
int data;//结点存储的数据
int height;//结点的高度
struct AVLNode* left;//左孩子指针
struct AVLNode* right;//右孩子指针
}AVLNode;
//顺序表结构体
typedef struct {
BSTNode* data[MAX_SIZE];//顺序表数组指针
int length;//顺序表长度
}SeqList;
//二叉链表
//二叉排序树的操作
BSTNode* createNode(int data);//创建一新结点
BSTNode* insertBST(BSTNode* root, int data);//插入一个结点到二叉排序树
void inorderTraversal(BSTNode* root);//中序遍历二叉排序树
float averageSearchLenth(BSTNode* root, int level);//计算二叉排序树的平均查找长度
BSTNode* deleteNode(BSTNode* root, int data);//在二叉排序树中查找并删除指定元素
//平衡二叉树的操作
int getHeight(AVLNode* node);//计算树的高度
int getmax(int a, int b);//比较两者获取最大值
AVLNode* createAVLNode(int data);//创建一个平衡二叉树结点
AVLNode* insertAVL(AVLNode* root, int data);//插入一个结点到平衡二叉树
void inorderTraversalAVL(AVLNode* root);//中序遍历平衡二叉树
float averageSearchLengthAVL(AVLNode* root, int level);//计算平衡二叉树的平均查找长度
AVLNode* deleteNodeAVL(AVLNode* root, int data);//删除平衡二叉树内指定的元素
AVLNode* rotateRight(AVLNode* tree);//右旋转
AVLNode* rotateLeft(AVLNode* tree);//左旋转
AVLNode* rotateRight_Left(AVLNode* tree);//先右旋,再左旋
AVLNode* rotateLeft_Right(AVLNode* tree);//先左旋,再右旋
int getBalanceFactor(AVLNode* node);//获取平衡因子
//顺序表构建二叉排序树
void insertSeqList(SeqList* list, BSTNode* node);//在顺序表中插入一个结点
BSTNode* buildBSTFromSeqList(SeqList* List);//根据顺序表构建二叉排序树
BSTNode* createNode(int data) {
BSTNode* newnode = (BSTNode*)malloc(sizeof(BSTNode));
newnode->data = data;
newnode->left = NULL;
newnode->right = NULL;
return newnode;
}
BSTNode* insertBST(BSTNode* root, int data) {
if (!root) {//如果 root 不存在
root=createNode(data);//创建一个新结点为根结点
}
else if(data<root->data) {
root->left = insertBST(root->left, data);//如果插入值小于当前结点的值,则递归插入到左子树
}
else if (data > root->data) {
root->right = insertBST(root->right, data);//如果插入值大于当前结点的值,则递归插入到右子树
}
else {
return root;//重复的值不插入
}
return root;
}
void inorderTraversal(BSTNode* root) {
if (root) {//用递归实现中序遍历
inorderTraversal(root->left);//递归遍历左子树
printf("%d", root->data);//输出当前结点的值
inorderTraversal(root->right);//递归遍历右子树
}
}
float averageSearchLenth(BSTNode* root,int level) {
static int sum=0;
static int count=0;
if (root != NULL) {
sum += level;//累加每个结点的层级
count++;//统计结点个数
averageSearchLenth(root->left, level + 1);//递归遍历左子树
averageSearchLenth(root->right, level + 1);//递归遍历右子树
}
//返回平均查找长度
return (float)sum / count;
}
BSTNode* deleteNode(BSTNode* root, int data) {
if (root == NULL) {
//树为空,没有找到要删除的结点
printf("无%d\n",data);
return root;
}
if (data < root->data) {
//在左子树中递归删除结点
root->left = deleteNode(root->left, data);
}
else if (data > root->data) {
//在右子树中递归删除结点
root->right = deleteNode(root->right, data);
}
else {
//找到了要删除的结点
if (root->left == NULL) {
//如果该结点没有左孩子,直接将右孩子接入其父结点
BSTNode* temp = root->right;
free(root);
return temp;
}
else if (root->right == NULL) {
//如果该结点没有右孩子,直接将左孩子接入其父结点
BSTNode* temp = root->left;
free(root);
return temp;
}
//如果该结点有两个子树,找到右子树中的最小结点(或左子树中最大的结点)替换当前要删除
的结点
BSTNode* minNode = root->right;
while (minNode->left!= NULL) {
minNode = minNode->left;
}
root->data = minNode->data;//用右子树中最小的结点替换当前结点
root->right=deleteNode(root->right, minNode->data);//删除右子树中最小的结点
}
return root;
}
int getHeight(AVLNode* node) {
if (node == NULL)
return 0;
return node->height;
}
int getmax(int a, int b) {
return (a > b) ? a : b;
}
AVLNode* createAVLNode(int data) {
AVLNode* newnode = (AVLNode*)malloc(sizeof(AVLNode));
newnode->data = data;
newnode->left = NULL;
newnode->right = NULL;
newnode->height = 1;
return newnode;
}
AVLNode* rotateRight(AVLNode* tree) {
//传入 tree 是根结点,也是失衡结点
//k 是我最终要返回的结点
AVLNode* k = tree->left;
tree->left = k->right;//将 tree 的左孩子指针指向 k 的右孩子
k->right = tree;//将 k 的右孩子指针指向 tree,实现右转
//旋转完成以后,调整树的高度
//需要通过左右子树的深度来调整被旋转结点的深度
tree->height = getmax(getHeight(tree->left), getHeight(tree->right)) + 1;
k->height = getmax(getHeight(k->left), getHeight(k->right)) + 1;
return k;//此时 k 为根结点
}
AVLNode* rotateLeft(AVLNode* tree) {
//传入 tree 是根结点,也是失衡结点
//k 是我最终要返回的结点
AVLNode* k = tree->right;
tree->right = k->left;//将 tree 的右孩子指针指向 k 的左孩子
k->left = tree;//将 k 的左孩子指针指向 tree,实现左转
//旋转完成以后,调整树的高度
//需要通过左右子树的深度来调整被旋转结点的深度
tree->height = getmax(getHeight(tree->left), getHeight(tree->right)) + 1;
k->height = getmax(getHeight(k->left), getHeight(k->right)) + 1;
return k;//此时 k 为根结点
}
AVLNode* rotateRight_Left(AVLNode* tree) {
//在右孩子的左子树中插入一个结点导致失衡的情况
tree->right = rotateRight(tree->right);//以右孩子为根结点将右子树右旋
tree = rotateLeft(tree);//自身左旋
return tree;
}
AVLNode* rotateLeft_Right (AVLNode* tree) {
//在左孩子的右子树中插入一个结点导致失衡的情况
tree->left = rotateLeft(tree->left);//以左孩子为根结点将左子树左旋
tree = rotateRight(tree);//自身右旋
return tree;
}
int getBalanceFactor(AVLNode* node) {
if (node == NULL) {
return 0;
}
return getHeight(node->left) - getHeight(node->right);
}
AVLNode* insertAVL(AVLNode* root, int data) {
if (root == NULL) {// 如果根结点不存在,创建一个新结点为根结点
return createAVLNode(data);
}
else if (data < root->data) {//如果插入值小于当前结点的值,则递归插入到左子树
root->left = insertAVL(root->left, data);
}
else if (data > root->data) {//如果插入值大于当前结点的值,则递归插入到右子树
root->right = insertAVL(root->right, data);
}
else {
//重复的值不添加
return root;
}
//调整新结点的高度
root->height = 1 + getmax(getHeight(root->left), getHeight(root->right));
int balance = getBalanceFactor(root);//获取新结点的平衡因子,判断是否失衡
if (balance > 1 && data < root->left->data) {//在左孩子的左子树中插入新结点的情况
return rotateRight(root);
}
if (balance > 1 && data > root->left->data) {//在左孩子的右子树中插入新结点的情况
return rotateLeft_Right(root);
}
if (balance < -1 && data < root->right->data){//在右孩子的左子树中插入新结点的情况
return rotateRight_Left(root);
}
if (balance < -1 && data > root->right->data) {//在右孩子的右子树中插入新结点的情况
return rotateLeft(root);
}
return root;
}
void inorderTraversalAVL(AVLNode* root) {
if (root) {//递归实现平衡二叉树中序遍历
inorderTraversalAVL(root->left);//递归遍历左子树
printf("%d", root->data);//输出当前结点的值
inorderTraversalAVL(root->right);//递归遍历右子树
}
}
float averageSearchLengthAVL(AVLNode* root, int level) {
static int sum = 0;
static int count = 0;
if (root != NULL) {
sum += level;//累加每个结点的层级
count++;//统计结点个数
averageSearchLengthAVL(root->left, level + 1);//递归遍历左子树
averageSearchLengthAVL(root->right, level + 1);//递归遍历右子树
}
//返回平均查找长度
return (float)sum / count;
}
AVLNode* deleteNodeAVL(AVLNode* root, int data) {
if (root == NULL) {//根结点不存在的情况
printf("无%d", data);
return root;
}
if (data < root->data) {
//在左子树中递归删除结点
root->left = deleteNodeAVL(root->left, data);
}
else if (data > root->data) {
//在右子树中递归删除结点
root->right = deleteNodeAVL(root->right, data);
}
else {
//找到要删除的结点
if (root->left == NULL) {
//如果该结点没有左孩子,直接将右孩子接入其父结点
AVLNode* temp = root->right;
free(root);
return temp;
}
else if (root->right == NULL) {
//如果该结点没有右孩子,直接将左孩子接入其父结点
AVLNode* temp = root->left;
free(root);
return temp;
}
else {
//若左右孩子都存在,找到右子树中最小的结点替换该结点
AVLNode* minNode = root->left;
while (minNode->left) {
minNode = minNode->left;
}
root->data = minNode->data;
root->right = deleteNodeAVL(root->right, minNode->data);
}
}
root->height = 1+getmax(getHeight(root->left), getHeight(root->right));//调整根结点高度
int balance = getBalanceFactor(root);//获取平衡因子,判断是否失衡
if (balance > 1 && getBalanceFactor(root->left) >= 0 ) {//左左情况
return rotateRight(root);
}
if (balance > 1 && getBalanceFactor(root->left) < 0 ) {//左右情况
return rotateLeft_Right(root);
}
if (balance < 1 && getBalanceFactor(root->right) <= 0) {//右右情况
return rotateLeft(root);
}
if (balance < 1 && getBalanceFactor(root->right) > 0) {//右左情况
return rotateRight_Left(root);
}
return root;
void insertSeqList(SeqList* list, BSTNode* node) {
if (list->length == MAX_SIZE) {
printf("顺序表已满\n");
return;
}
list->data[list->length++] = node;
}
BSTNode* buildBSTFromSeqList(SeqList* list) {
BSTNode* root = NULL;//根结点
for (int i = 0; i < list->length; i++) {//遍历顺序表中所有的元素
BSTNode* node = list->data[i];//设置 node 作为临时变量保存当前需要插入的结点
if (root == NULL) {//若根结点不存在,则将 node 作为根结点
root = node;
}
else {
BSTNode* current = root;//从根结点开始向下比较
while (1) {
if (node->data < current->data) {//若 node 的值比 current 小,则与 current 的左子树中的
值作比较
if (current->left == NULL) {//左子树为空,直接插入
current->left = node;
break;
}
else {//左子树不为空,则将 current 指针指向他的左孩子
current = current->left;
}
}
else {//若 node 的值比 current 大,则与 current 的右子树中的值作比较
if (current->right == NULL) {//右子树为空,直接插入
current->right = node;
break;
}
else {//右子树不为空,则将 current 指针指向他的右孩子
current = current->right;
}
}
}
}
}
return root;
}
int main() {
//二叉排序树
BSTNode* T1 = NULL;
//从文本文件中读取整数序列并生成二叉排序树
FILE* file = fopen("./L.txt","r");//打开本文文件 L.txt
if (file == NULL) {//如果文件不存在
printf("无法打开文件\n");
return 0;
}
int num;
while (fscanf(file, "%d", &num) != EOF) {
T1 = insertBST(T1, num);//建立二叉排序树
}
fclose(file);
//中序遍历二叉排序树
printf("该二叉树的中序遍历结果为:");
inorderTraversal(T1);
printf("\n");
//计算二叉排序树的平均查找长度
float average_Search_Lenth = averageSearchLenth(T1,1);
printf("该二叉树的平均查找长度为:%f",average_Search_Lenth);
printf("\n");
//查找并删除指定元素结点
int x;
printf("输入要删除的元素:");
scanf("%d", &x);
T1 = deleteNode(T1, x);
//中序遍历删除结点后的二叉排序树
printf("删除元素后的二叉排序树的中序遍历结果为:");
inorderTraversal(T1);
printf("\n");
//平衡二叉树
AVLNode* BT = NULL;
file= fopen("./L.txt", "r");
if (file == NULL) {
printf("无法打开文件\n");
return 0;
}
while (fscanf(file, "%d", &num) != EOF) {
BT = insertAVL(BT, num);
}
fclose(file);
printf("平衡二叉树的中序遍历结果:");
inorderTraversalAVL(BT);
printf("\n");
float average_LenthAVL = averageSearchLengthAVL(BT, 1);
printf("平衡二叉树的平均查找长度为:%f", average_LenthAVL);
printf("\n");
printf("输入要查找并删除的元素:");
scanf("%d", &x);
BT = deleteNodeAVL(BT, x);
printf("删除元素后的平衡二叉树的中序遍历结果为:");
inorderTraversalAVL(BT);
printf("\n");
//顺序表
SeqList list;
list.length = 0;
file= fopen("L.txt", "r");
if (file == NULL) {
printf("无法打开文件\n");
return 0;
}
while (fscanf(file, "%d", &num) != EOF) {
BSTNode* newNode = createNode(num);
insertSeqList(&list, newNode);
}
fclose(file);
BSTNode*T2=NULL;
T2 = buildBSTFromSeqList(&list);
printf("该二叉树的中序遍历结果为:");
inorderTraversal(T2);
printf("\n");
average_Search_Lenth = averageSearchLenth(T2, 1);
printf("该二叉树的平均查找长度为:%f", average_Search_Lenth);
printf("\n");
printf("输入要删除的元素:");
scanf("%d", &x);
T2 = deleteNode(T2, x);
printf("删除元素后的二叉排序树的中序遍历结果为:");
inorderTraversal(T2);
printf("\n");
return 0;
}