二叉查找树
- 输入为一组未排序的结点序列(类型为整数,用做结点的键值),生成由它们作结点键值
的一棵查找树(结点未排序,依次插入树中)。 - 中序输出这棵查找树。
- 判断这棵查找树是否平衡。
- 计算这棵查找树查找结点的平均比较次数(假设每个结点的使用概率相同,且每次查找
都是一次成功的查找)。
参考公式:
AVG(二叉查找法)= ∑树中的𝒌𝒑(𝒌)(𝟏 + 𝝀𝒌)
输入格式:
第一行输入一个正整数𝑛 (𝑛 ≤ 1000)表示结点数量。
第二行输入 n 个整数表示未排序的结点序列,每个数之间用空格隔开。
输出格式:
第一行中序输出这棵查找树。
第二行判断这棵查找树是否平衡,如果是输出“Yes”,否则输出“No”(不用输出引号)。
第三行输出这颗查找树查找结点的平均比较次数,结果保留 6 位小数。
示例: input 5
3 5 1 2 4 output
1 2 3 4 5
Yes
2.200000
#include <bits/stdc++.h>
using namespace std;
typedef struct binarySortTree {
int data;
struct binarySortTree* lchild;
struct binarySortTree* rchild;
} BiNODE;
// 链式存储
typedef struct snode
{
BiNODE* node;
int lev; //用于层次遍历中记录结点的层数
struct snode* next;
}Snode;
// 将结点递归放入查找树
BiNODE* Insert(BiNODE* root, int x)
{
if (!root)
{
BiNODE* t = new BiNODE;
t->data = x;
t->lchild = NULL;
t->rchild = NULL;
root = t;
}
else if (x < root->data)
{
root->lchild = Insert(root->lchild, x);
}
else if (x > root->data)
{
root->rchild = Insert(root->rchild, x);
}
return root;
}
/**
* 建立一颗以nodeArr作为结点键值的一棵查找树
* 数组下标从1开始
* @param nodeArr [大小为arrSize的数组]
* @param arrSize [数组大小]
*
* @return [树的根节点root的指针]
*/
BiNODE* buildTree(int* nodeArr, int arrSize)
{
BiNODE* root = NULL;
for (int i = 1; i <= arrSize; i++)
root = Insert(root, nodeArr[i]);
return root;
}
/**
* 中序输出这棵查找树
* 无返回值, 输出一行, 数与数之间有空格, 行末无多余空格
* 具体参考文档上的样例
* @param root [树的根节点]
*/
void printInOrder(BiNODE* root)
{
if (!root) return;
BiNODE* p = root;
Snode* top = NULL;
Snode* t = NULL;
int flag = 1;
// 用于判断当前结点是否为第一个输出的结点,
// 第一个:空格+data
// 非第一个:data
while (p || top)
{
while (p)
{
t = new Snode;
t->node = p;
t->next = top;
top = t; // 更新栈顶为新压入的结点
p = p->lchild; // 直到找到最后一个左子树
}
if (top)
{
p = top->node;
if (flag) // 是第一个
{
printf("%d", p->data);
flag = 0;
}
else
{
printf(" %d", p->data);
}
t = top;
top = top->next;
delete t;
p = p->rchild; // 处理右子树
}
}
printf("\n");
}
// 递归判断是否平衡树
bool isBalance(BiNODE* root, int& depth)
{
// 检查子树的深度差是否小于1
if (!root) // 空树为平衡树
{
depth = 0;
return true;
}
int ld = 0, rd = 0;
// 子树中有不平衡树,那么本树不平衡
if (!isBalance(root->lchild,ld) || !isBalance(root->rchild,rd))
return false;
// 子树深度差>1,那么本树不平衡
if (abs(ld - rd) > 1)
return false;
// 本树的深度为子树中深度最大值+1
depth = ld > rd ? ld + 1 : rd + 1;
return true;
}
/**
* 判断这棵查找树是否平衡
* 如果是输出"Yes", 否则输出"No"(不用输出引号)
* 具体参考文档上的样例
* @param root [树的根节点]
*/
void printIsBalance(BiNODE* root)
{
int depth = 0;
if (isBalance(root, depth))
printf("Yes\n");
else printf("No\n");
}
/**
* 输出这颗查找树查找结点的平均比较次数, 结果保留6位小数
* 具体参考文档上的样例
* @param root [树的根节点]
*/
void printAVG(BiNODE* root)
{
if (!root)
printf("0.000000\n");
else
{
Snode* head = new Snode;
head->lev = 1; // 根结点层数为1
head->node = root;
head->next = NULL;
Snode* tail = head;
double sum = 0, num = 0;
while (head!=NULL)
{
// 左右孩子入队
if (head->node->lchild)
{
Snode* r = new Snode;
r->node = head->node->lchild;
r->next = NULL;
r->lev = head->lev + 1;
tail->next = r; // 子结点进入队列尾部
tail = r;
}
if (head->node->rchild)
{
Snode* r = new Snode;
r->node = head->node->rchild;
r->next = NULL;
r->lev = head->lev + 1;
tail->next = r; // 子结点进入队列尾部
tail = r;
}
// 出队
Snode* r = head;
sum += head->lev;
num++;
head = head->next;
delete r;
}
printf("%.6f\n", sum / num);
}
}
int main() {
int n;
scanf("%d", &n);
int* nodeArr = (int*)malloc((n + 1) * sizeof(int));
for (int i = 1; i <= n; ++i) {
scanf("%d", &nodeArr[i]);
}
BiNODE* root = buildTree(nodeArr, n);
printInOrder(root);
printIsBalance(root);
printAVG(root);
return 0;
}
堆排序
- 输入为一组未排序的结点(类型为整数)序列,建大顶堆。
- 通过交换及调整堆完成堆排序。输出排序后的结点序列。
- 分别输出“建堆”和“交换调整”过程中的交换次数。
输入格式:
第一行输入一个正整数𝑛 (𝑛 ≤ 1000)表示结点数量。
第二行输入 n 个整数表示未排序的结点序列,数与数之间用空格隔开。
输出格式:
第一行输出 n 个整数表示排序后的结点序列。
第二行输出 2 个整数,分别表示“建堆”和“交换调整”过程的交换次数。
示例: Input 5
3 5 1 2 4
Output
1 2 3 4 5
2 7
#include <bits/stdc++.h>
using namespace std;
/**
* 给定一组未排序的结点(类型为整数)序列, 建一个大顶堆
* 同时计算建堆时的交换次数
* 数组下标从0开始
* @param arr [大小为arrSize的数组]
* @param arrSize [数组大小]
*
* @return [建堆过程中的交换次数]
*/
int siftdown(int* a, int i, int n)
// 调整以a[i]为根的二叉树使之成为堆
// 堆的各子树也为堆
{
int sum = 0;
int j;
int t = a[i];
//int j = 2 * i + 1;
while ((j=2*i+1)<n)
{
// 挑选左右孩子中更大的结点
if (j < n - 1 && a[j] < a[j + 1])
j++;
if (t < a[j]) // 如果t比孩子小
{
a[i] = a[j];
i = j;
sum++;
}
else break;
}
a[i] = t;
return sum;
}
int buildHeap(int* arr, int arrSize)
{
int sum = 0;
for (int i = (arrSize - 2) / 2; i >= 0; i--)
sum += siftdown(arr, i, arrSize);
return sum;
}
/**
* 给定一个大小为arrSize的未排序的堆, 输出堆排序后的序列
* 同时计算堆排序过程中的交换次数
* @param arr [大小为arrSize的堆]
* @param arrSize [堆的大小]
*
* @return [堆排序过程中的交换次数]
*/
int heapSort(int* arr, int arrSize)
{
if (arrSize == 0) return 0;
int sum = 0;
int sum1 = buildHeap(arr, arrSize);
for (int m = arrSize - 1; m >= 1; m--)
{
int tmp = arr[0];
arr[0] = arr[m];
arr[m] = tmp;
sum+=(1+siftdown(arr, 0, m));
}
for (int i = 0; i < arrSize; i++)
printf("%d%c", arr[i], i == arrSize - 1 ? '\n' : ' ');
return sum;
}
int main() {
int n;
scanf("%d", &n);
int* arr = (int*)malloc((n) * sizeof(int));
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}
int buildSwapCnt = buildHeap(arr, n);
int sortSwapCnt = heapSort(arr, n);
printf("%d %d\n", buildSwapCnt, sortSwapCnt);
//输出排好序的序列
return 0;
}
平衡查找树
用前序+中序的方法输入一棵二叉树,建树,树结点的结构包括:键值,平衡度和左右子树指针。
- 判断输入的二叉树是否为平衡的查找树(分别判断是否是平衡树,是否是查找树)。
注:输出 Yes or No - 二叉树建立完成后,编写函数,通过仅“跟踪”到叶子结点的一条路径,而不查看树中
所有的结点,返回树的高度并输出这条路径。输出高度及路径
例:输入
前序:70 30 20 10 50 40 60 100 90 80 110 120
中序:10 20 30 40 50 60 70 80 90 100 110 120
struct node { //包括结点键值,结点的平衡度,左子结点指针,右子结点指针
}
输入格式:
第一行输入一个正整数𝑛 (𝑛 ≤ 1000)表示二叉树的结点数量。
第二行输入 n 个整数表示二叉树的前序遍历序列,数与数之间用空格隔开。
第二行输入 n 个整数表示二叉树的中序遍历序列,数与数之间用空格隔开。
输出格式:
第一行判断输入的二叉树是否平衡,如果是输出“Yes”,否则输出“No”(不用输出引
号)。
第二行判断输入的二叉树是否是排序树,如果是输出“Yes”,否则输出“No”(不用输
出引号)。
第三行输出问题 2 中的路径,输出 n 个数,数与数之间用空格隔开。 第四行输出问题 2 中树的层数。
示例: Input 12
7 3 2 1 5 4 6 10 9 8 11 12
1 2 3 4 5 6 7 8 9 10 11 12
Output
Yes
Yes
7 10 11 12 4
在这里插入代码片#include <bits/stdc++.h>
using namespace std;
typedef struct binarySortTree {
int data; //结点的数据
int BF; //结点的平衡因子
struct binarySortTree* lchild;
struct binarySortTree* rchild;
}BiNODE;
/**
* 给定二叉树的前序和中序遍历序列, 建立一棵二叉树
* 数组下标从1开始
* @param preOrder [大小为arrSize的前序遍历序列]
* @param inOrder [大小为arrSize的中序遍历序列]
* @param arrSize [序列的长度]
*
* @return [树的根节点root]
*/
// 递归获得结点的平衡度
// 与获得树深度函数非常类似
int getBF(BiNODE* root)
{
if (!root) // 仅根节点时高度为0
return -1;
int rd = getBF(root->rchild);
int ld = getBF(root->lchild);
root->BF = rd - ld;
int depth = rd > ld ? rd + 1 : ld + 1;
return depth;
}
// 递归调用
BiNODE* buildTreePreInRe(int pre[], int head1, int tail1,
int in[], int head2, int tail2)
{
if (tail2 < head2)
return NULL;
int i = head2;
for (; i <= tail2; i++)
{
if (in[i] == pre[head1])
break;
}
BiNODE* root = new BiNODE;
root->data = pre[head1];
root->lchild = buildTreePreInRe(pre, head1 + 1, head1 + i - head2, in, head2, i - 1);
root->rchild = buildTreePreInRe(pre, head1 + i - head2 + 1, tail1, in, i + 1, tail2);
return root;
}
BiNODE* buildBTree(int* preOrder, int* inOrder, int arrSize)
{
if (arrSize == 0) return NULL;
BiNODE* root = buildTreePreInRe(preOrder, 1, arrSize, inOrder, 1, arrSize);
int depth = getBF(root); // root->BF已在getBF中改变
return root;
}
/**
* 给定二叉树的根节点, 判断该树是否平衡
* 如果是输出“Yes”,否则输出“No”(不用输出引号)
* @param root [二叉树的根节点]
*/
bool isBalance(BiNODE* root)
{
if (!root)
return true;
if (root->BF > 1 || root->BF < -1)
return false;
if (!isBalance(root->lchild) || !isBalance(root->rchild))
return false;
return true;
}
void printIsBalance(BiNODE* root)
{
if (isBalance(root))
printf("Yes\n");
else printf("No\n");
}
/**
* 给定二叉树的根节点, 判断该树是否为搜索树
* 如果是输出“Yes”,否则输出“No”(不用输出引号)
* @param root [二叉树的根节点]
*/
int former = -1;
bool isSearchTree(BiNODE* root)
{
if (!root)
return true;
if (!isSearchTree(root->lchild))
return false;
if (root->data < former)
return false;
former = root->data;
if (!isSearchTree(root->rchild))
return false;
return true;
}
void printIsSearchTree(BiNODE* root)
{
if (isSearchTree(root))
printf("Yes\n");
else printf("No\n");
}
/**
* 给定二叉树的根节点, 通过仅“跟踪”到叶子结点的一条路径
* 而不查看树中所有的结点, 返回树的高度并输出这条路径。
* @param root [二叉树的根节点]
*
* @return [树的高度]
*/
int getTreeHeight(BiNODE* root)
{
if (!root)
{
cout << endl;
return -1;
}
printf("%d ", root->data);
int ld = 0, rd = 0;
if (root->BF >= 0) // (靠右策略)右子树更深
{
rd = getTreeHeight(root->rchild);
}
else // 左子树更深
{
ld = getTreeHeight(root->lchild);
}
int depth = rd > ld ? rd + 1 : ld + 1;
return depth;
}
int main() {
int n;
scanf("%d", &n);
int* preOrder = (int*)malloc((n + 1) * sizeof(int));
int* inOrder = (int*)malloc((n + 1) * sizeof(int));
for (int i = 1; i <= n; ++i) {
scanf("%d", &preOrder[i]);
}
for (int i = 1; i <= n; ++i) {
scanf("%d", &inOrder[i]);
}
BiNODE* root = buildBTree(preOrder, inOrder, n);
printIsBalance(root);
printIsSearchTree(root);
int treeHeight = getTreeHeight(root);
printf("%d\n", treeHeight);
return 0;
}