跳转至

15.5 一些代码

阅读信息

850 个字  8 分钟  本页总访问量:加载中...

课上复习

线性表 顺序存储:数组 链式存储:链表 数组与链表存储的优缺点 链表的操作 典型习题:实现单链表的原地逆转(循环不变式), 分别用一元多项式的两种表示实现多项式加法

堆栈 顺序栈:数组,top++, top-- lianzhan:链表,top 即头指针 应用:括号匹配检验,表达式求值,n 节汉诺塔问题(典型递归),迷宫问题 快速排序递归用堆栈怎么实现?每次递归偶参数,这个参数代表起点终点大小,一种方法将参数压到堆栈中,每次循环从堆栈中抛出元素,拆成两个再压到堆栈中 可以把所有递归用循环实现,核心是将参数压到堆栈中 迷宫问题:用数组表示迷宫,0 表示通路,1 表示墙。一直沿着某个方向走。每次将(位置坐标,方向选择)压栈,回头表示先不断压栈再不断抛出。回溯法。

两个堆栈实现队列 入队: 如果栈 1 满但栈 2 空,将栈 1 中元素倒入栈 2,再将新元素放入栈 1 如果栈 1 有元素但没满,将栈 2 倒回栈 1,再新元素入栈 出队: 如果栈 2 有元素,直接抛出 如果栈 2 空,将栈 1 所有元素倒入栈 2,再抛出

再一个数组中表示两个堆栈,实现空间共享: 两头表示两个堆栈,从两边向中间放。满的判定:top_right == top_left + 1

树,level 和 degree 中序遍历时,n 在 m 前的条件是:n 在 m 的左方 任意两点之间路径的长度的最大值定义未树的直径。给定树求直径

给定链表表示的二叉树,判断其是否为完全二叉树

左边是查找树,右边是查找树,根节点比左儿子打,比右儿子小,是不是查找树? 不是 左边是堆,右边是堆,根比左右儿子大,是不是堆? 是

设计算法,判断一个序列可不可能是查找顺序 初始为负无穷到正无穷。每次碰到小的元素,更新左边界;碰到大的元素,更新右边界。

树的双亲表示法和孩子表示法,左儿子右兄弟表示法。

图的表示:邻接矩阵,邻接表,逆邻接表,十字链表(有向图)

用 Floyd 算法判断图是否有回路? Floyd:邻接矩阵的幂相加。检查对角线上元素,如果对角线上有非零元,则有环。

给定村庄和不同村庄间道路的长度。寻找位置,使其到各个村庄的距离之和最小。

哈希,求等概率成功与不成功查找的平均查找次数。

给定哈希函数和哈希结果,求最小的输入序列:构建有向图,求最小的拓扑序列

排序的辅助空间 堆排序:无辅助空间 快速排序:递归需要栈空间 归并排序:额外需要数组

排序算法是否稳定:需要交换的肯定不稳定

很大的数据,在不完全排序的前提下找出前 m 小的元素: 建立大小为 m 的堆,将所有元素依次插入

用快速排序找到第 k 大的元素

快速排序的非递归算法? 将递归转化为循环?

一些代码

BST.c

C
#include <stdio.h>
#include <stdlib.h>

typedef int ElementType;
typedef struct TNode* Position;
typedef Position BinTree; /* 二叉树类型 */
struct TNode {            /* 树结点定义 */
    ElementType Data;     /* 结点数据 */
    BinTree Left;         /* 指向左子树 */
    BinTree Right;        /* 指向右子树 */
};

Position Find(ElementType X, BinTree BST) {
    if (!BST)
        return NULL; /*查找失败*/
    if (X > BST->Data)
        return Find(X, BST->Right); /*在右子树中继续查找*/
    else if (X < BST->Data)
        return Find(X, BST->Left); /*在左子树中继续查找*/
    else                           /* X == BST->Data */
        return BST;                /*查找成功,返回结点的找到结点的地址*/
}

Position IterFind(ElementType X, BinTree BST) {
    while (BST) {
        if (X > BST->Data)
            BST = BST->Right; /*向右子树中移动,继续查找*/
        else if (X < BST->Data)
            BST = BST->Left; /*向左子树中移动,继续查找*/
        else                 /* X == BST->Data */
            return BST;      /*查找成功,返回结点的找到结点的地址*/
    }
    return NULL; /*查找失败*/
}

Position FindMin(BinTree BST) {
    if (!BST)
        return NULL; /*空的二叉搜索树,返回NULL*/
    else if (!BST->Left)
        return BST; /*找到最左叶结点并返回*/
    else
        return FindMin(BST->Left); /*沿左分支继续查找*/
}

Position FindMax(BinTree BST) {
    if (BST)
        while (BST->Right) /*沿右分支继续查找,直到最右叶结点*/
            BST = BST->Right;
    return BST;
}

BinTree Insert(BinTree BST, ElementType X) {
    if (!BST) { /* 若原树为空,生成并返回一个结点的二叉搜索树 */
        BST = (BinTree)malloc(sizeof(struct TNode));
        BST->Data = X;
        BST->Left = BST->Right = NULL;
    } else { /* 开始找要插入元素的位置 */
        if (X < BST->Data)
            BST->Left = Insert(BST->Left, X); /*递归插入左子树*/
        else if (X > BST->Data)
            BST->Right = Insert(BST->Right, X); /*递归插入右子树*/
        /* else X已经存在,什么都不做 */
    }
    return BST;
}

BinTree Delete(BinTree BST, ElementType X) {
    Position Tmp;
    if (!BST)
        printf("要删除的元素未找到");
    else {
        if (X < BST->Data)
            BST->Left = Delete(BST->Left, X); /* 从左子树递归删除 */
        else if (X > BST->Data)
            BST->Right = Delete(BST->Right, X); /* 从右子树递归删除 */
        else {                                  /* BST就是要删除的结点 */
            /* 如果被删除结点有左右两个子结点 */
            if (BST->Left && BST->Right) {
                /* 从右子树中找最小的元素填充删除结点 */
                Tmp = FindMin(BST->Right);
                BST->Data = Tmp->Data;
                /* 从右子树中删除最小元素 */
                BST->Right = Delete(BST->Right, BST->Data);
            } else { /* 被删除结点有一个或无子结点 */
                Tmp = BST;
                if (!BST->Left) /* 只有右孩子或无子结点 */
                    BST = BST->Right;
                else /* 只有左孩子 */
                    BST = BST->Left;
                free(Tmp);
            }
        }
    }
    return BST;
}

表达式树

C
/*
二元表达式可以很自然的联系到二叉树:
以基本运算对象作为叶节点中的数据,
以运算符作为非叶节点中的数据,
其两棵子树是它的运算对象,
子树可以是基本运算对象,也可以是复杂表达式.

算式表达式和表达式树的关系如下:
    表达式树的先根遍历:前缀表达式
    表达式树的中根遍历:中缀表达式
    表达式树的后根遍历:后缀表达式

构建表达式树:
1. 给定一个表达式的中缀形式:(4+1*(5-2))-6/3
2. 首先将每个运算加上括号,区分优先级,得到(4+(1*(5-2)))-(6/3)
3. 括号外的-优先级最低,作为根节点,(4+(1*(5-2)))作为左子树,(6/3)作为右子树;
4. 递归的转换4+(1*(5-2)),+最为根节点,4是左子树,
    (1*(5-2))是右子树。*是右子树的根节点,1是左子树,(5-2)是右子树。
    最后计算(5-2),-是根节点,5是左子树,2是右子树。
构造好表达式树之后,前缀表达式和中缀表达式可根据先根遍历和后根遍历得到。
    前缀表达式:- + 4 * 1 - 5 2 / 6 3
    后缀表达式:4 1 5 2 - * + 6 3 / -
*/

#include <stdio.h>
#define MAXN 1000

int lch[MAXN], rch[MAXN];
char op[MAXN];
int nc = 0;  // 结点数

int build_tree(char* s, int x, int y) {
    int i, c1 = -1, c2 = -1, p = 0;
    int u;
    if (y - x == 1)  // 仅一个字符,建立单独结点
    {
        u = ++nc;
        lch[u] = rch[u] = 0;
        op[u] = s[x];
        return u;
    }
    for (i = x; i < y; i++) {
        switch (s[i]) {
            case '(':
                p++;
                break;
            case ')':
                p--;
                break;
            case '+':
            case '-':
                if (!p)
                    c1 = i;
                break;
            case '*':
            case '/':
                if (!p)
                    c2 = i;
                break;
        }
    }
    if (c1 < 0)
        c1 = c2;  // 找不到括号外的加减号,就用乘除号
    if (c1 < 0)
        return build_tree(s, x + 1, y - 1);  // 整个表达式被一对括号括起来
    u = ++nc;
    lch[u] = build_tree(s, x, c1);
    rch[u] = build_tree(s, c1 + 1, y);
    op[u] = s[c1];
    return u;
}

线索二叉树

C
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

// 线索二叉树
typedef struct ThreadNode {
    int data;
    struct ThreadNode *left, *right;
    int ltag, rtag;  // tag为0表示有孩子
} ThreadNode;

// 指向当前访问变量的前驱
ThreadNode* pre = NULL;

void visit(ThreadNode* node);

// 初始化节点
ThreadNode* initNode() {
    ThreadNode* Node = (ThreadNode*)malloc(sizeof(ThreadNode));
    Node->left = NULL;
    Node->right = NULL;
    Node->ltag = 0;  // 默认节点有左右孩子
    Node->rtag = 0;
    return Node;
}

// 插入新节点并赋值
bool insertNode(ThreadNode* node, int data, int contain) {
    ThreadNode* newNode = initNode();
    // contain为0时向左插入,为1时向右插入
    if (node->left == NULL && contain == 0) {
        node->left = newNode;
        newNode->data = data;
        return true;
    } else if (node->right == NULL && contain == 1) {
        node->right = newNode;
        newNode->data = data;
        return true;
    }
    free(newNode);
    return false;
}

// 边中序遍历边线索化二叉树
void InThread(ThreadNode* node) {
    if (node != NULL) {
        InThread(node->left);   // 遍历左子树
        visit(node);            // 访问根节点
        InThread(node->right);  // 遍历右子树
    }
}

// 创建中序线索化二叉树
void createInThread(ThreadNode* node) {
    // 重置全局变量
    pre = NULL;
    InThread(node);
    // 最后一个遍历的节点的后继设置为NULL
    pre->right = NULL;
    pre->rtag = 1;
}

// 找到以node为根的子树中,最先被中序遍历的节点
ThreadNode* FirstNode(ThreadNode* node) {
    // 当为空时
    if (node == NULL) {
        return NULL;
    }
    while (node->ltag == 0) {
        node = node->left;
    }
    return node;
}

// 找到以node为根的子树中,最后被中序遍历的节点
ThreadNode* LastNode(ThreadNode* node) {
    if (node == NULL) {
        return NULL;
    }
    while (node->rtag == 0) {
        node = node->right;
    }
    return node;
}

// 访问根节点
void visit(ThreadNode* node) {
    if (node->left == NULL) {
        node->left = pre;
        node->ltag = 1;
    }

    if (pre != NULL && pre->right == NULL) {
        pre->right = node;
        pre->rtag = 1;
    }
    pre = node;
}

// 在中序二叉树中找到p的后继节点
ThreadNode* NextNode(ThreadNode* p) {
    if (p->rtag == 0) {
        return FirstNode(p->right);
    }
    return p->right;
}

void visit0(ThreadNode* thread_node) {
    printf("%d  ", thread_node->data);
}

// 利用线索对二叉树进行非递归遍历
void Inorder(ThreadNode* rootNode) {
    for (ThreadNode* p = FirstNode(rootNode); p != NULL; p = NextNode(p)) {
        visit0(p);
    }
}

// 在中序二叉树中找到p的前驱节点
ThreadNode* BeforeNode(ThreadNode* p) {
    if (p->ltag == 0) {
        return LastNode(p->left);
    }
    return p->left;
}

// 利用线索对二叉树进行非递归逆序遍历
void InorderNi(ThreadNode* rootNode) {
    for (ThreadNode* p = LastNode(rootNode); p != NULL; p = BeforeNode(p)) {
        visit0(p);
    }
}

int main(void) {
    // 初始化二叉树
    ThreadNode* rootNode = initNode();
    // 测试根节点插入数据
    rootNode->data = 1;
    printf("根节点数据:%d\n", rootNode->data);
    // 测试往二叉树创建节点
    insertNode(rootNode, 2, 0);
    insertNode(rootNode, 3, 1);
    printf("第二层左节点数据:%d\n第二层右节点数据:%d\n", rootNode->left->data,
           rootNode->right->data);
    insertNode(rootNode->left, 4, 1);
    insertNode(rootNode->right, 5, 1);
    printf("第三层第一个节点右指针数据:%d\n第三层第二个节点右指针数据:%d\n",
           rootNode->left->right->data, rootNode->right->right->data);
    insertNode(rootNode->left->right, 6, 0);
    printf("第四层第一个节点左指针数据:%d\n",
           rootNode->left->right->left->data);

    createInThread(rootNode);

    printf("中序遍历:\n");
    Inorder(rootNode);
    printf("\n逆中序遍历:\n");
    InorderNi(rootNode);
}