2021秋季《数据结构》_第六章书面作业(基础练习)

二叉查找树

  1. 输入为一组未排序的结点序列(类型为整数,用做结点的键值),生成由它们作结点键值
    的一棵查找树(结点未排序,依次插入树中)。
  2. 中序输出这棵查找树。
  3. 判断这棵查找树是否平衡。
  4. 计算这棵查找树查找结点的平均比较次数(假设每个结点的使用概率相同,且每次查找
    都是一次成功的查找)。
    参考公式:
    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;
}

堆排序

  1. 输入为一组未排序的结点(类型为整数)序列,建大顶堆。
  2. 通过交换及调整堆完成堆排序。输出排序后的结点序列。
  3. 分别输出“建堆”和“交换调整”过程中的交换次数。
    输入格式:
    第一行输入一个正整数𝑛 (𝑛 ≤ 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;
}

平衡查找树

用前序+中序的方法输入一棵二叉树,建树,树结点的结构包括:键值,平衡度和左右子树指针。

  1. 判断输入的二叉树是否为平衡的查找树(分别判断是否是平衡树,是否是查找树)。
    注:输出 Yes or No
  2. 二叉树建立完成后,编写函数,通过仅“跟踪”到叶子结点的一条路径,而不查看树中
    所有的结点,返回树的高度并输出这条路径。输出高度及路径
    例:输入
    前序: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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值