数据结构:第7章:查找(复习)

news2025/2/24 10:39:38

目录

顺序查找:

折半查找:

二叉排序树:

4. (程序题)

平衡二叉树: 


顺序查找:

ASL=\frac{1}{n}\sum i=\frac{1+n}{2}

折半查找:

ASL=\frac{1}{n}\sum_{i=1}^{h}j*2^{j-1}=\frac{n+1}{n}log2(n+1)-1

这里 j 表示 二叉查找树的第 j 层

二叉排序树:

二叉排序树(Binary Search Tree,BST)是一种特殊的二叉树,定义:

  1. 对于二叉排序树的每个节点,其左子树的所有节点的值都小于该节点的值。
  2. 对于二叉排序树的每个节点,其右子树的所有节点的值都大于该节点的值。
  3. 对于二叉排序树的每个节点,其左右子树也分别是二叉排序树。

可以发现二叉排序树的定义时递归定义。

这些性质保证了对于二叉排序树中的任意节点,其左子树的节点值小于它,右子树的节点值大于它,从而形成了一种有序的结构。

二叉排序树的有序性质使得在其中进行查找、插入和删除等操作时具有较高的效率。对于给定的值,可以通过比较节点的值,按照二叉排序树的性质在树中快速定位所需的节点。

二叉排序树的难点在于删除树中的某个值。删除某个键值为 key 的节点时,有三中情况要考虑:

1.该节点 r 的左孩子为空:r=r->lch;

2.该节点 r 的右孩子为空:l=l->rch;

3.该节点的左右孩子均不位空:选择左孩子中 key 值最大的节点替换 r;

4. (程序题)

二叉排序树插入、删除

键盘输入若干整型数据,以0做结束,利用二叉排序树的插入算法创建二叉排序树,并中序遍历该二叉树。之后输入一个整数x,在二叉排序树中查找,若找到则输出“该数存在”,否则输出“该数不存在”;再输入一个要删除的一定存在的整数y,完成在该二叉树中删除y的操作,并输出删除y后的二叉树中序遍历的结果。

输出数据之间用一个空格分隔。

输入:
1 5 4 2 3 6 8 7 9 11 14 13 12 16 19 0
输出:
1 2 3 4 5 6 7 8 9 11 12 13 14 16 19
输入:
19
输出:
该数存在
输入:
14
输出:
1 2 3 4 5 6 7 8 9 11 12 13 16 19

#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<math.h>
#include<map>
#include<sstream>
#include<deque>
#include<unordered_map>
using namespace std;
typedef long long LL;

typedef struct Info {
	int key;
}Info;

typedef struct Node {
	Info data;
	struct Node* lch;
	struct Node* rch;
}Node,*Tree;

void print(Tree& r) {
	if (r == NULL)return;
	print(r->lch);
	cout << r->data.key << " ";
	print(r->rch);
}

void Insert(Tree& r, int key) {
	if (r == NULL) {
		Node* p = new Node;
		p->data.key = key;
		p->rch = p->lch = NULL;
		r = p;
	}
	else if(r->data.key<key) {
		Insert(r->rch, key);
	}
	else {
		Insert(r->lch, key);
	}
}

void build(Tree& r) {
	int in;
	cin >> in;
	while (in) {
		Insert(r, in);
		cin >> in;
	}
}

int search(Tree& r, int key) {
	if (r == NULL)return 0;
	if (r->data.key == key) {
		return 1;
	}
	if (r->data.key < key) {
		if (search(r->rch, key))return 1;
	}
	else {
		if (search(r->lch, key))return 1;
	}
	return 0;
}

int del(Tree& r, int key) {
	if (r == NULL)return 0;
	if (r->data.key == key) {
		if (r->lch == NULL) {
			r =r->rch;
		}
		else if (r->rch == NULL) {
			r =r->lch;
		}
		else {
			//cout << r->data.key << endl;
			Node* p = r->lch;
			Node* fa = r;
			
			while (p->rch != NULL) {
				fa = p;
				p = p->rch;
			}
			Node* t = r;
			if (fa != r)
				fa->rch = p->lch;
			if (r->lch != p)
				p->lch = r->lch;
			p->rch = r->rch;
			//cout << p->data.key << endl;
			r = p;
			delete t;
		}
		return 1;
	}
	if (r->data.key < key) {
		if (del(r->rch, key))return 1;
	}
	else {
		if (del(r->lch, key))return 1;
	}
	return 0;
}

int main() {
	Node* root = NULL;
	build(root);
	print(root);
	int in;
	cin >> in;
	if (search(root, in)) {
		cout << "该数存在" << endl;
	}
	else {
		cout << "该数不存在" << endl;
	}
	cin >> in;
	del(root, in);
	print(root);
	return 0;
}

用例1:

输入

1 5 4 2 3 6 8 7 9 11 14 13 12 16 19 0 19 14

输出

1 2 3 4 5 6 7 8 9 11 12 13 14 16 19 该数存在 1 2 3 4 5 6 7 8 9 11 12 13 16 19

用例2:

输入

10 9 8 7 11 12 13 14 0 14 8

输出

7 8 9 10 11 12 13 14 该数存在 7 9 10 11 12 13 14

用例3:

输入

23 45 67 21 12 15 9 10 55 0 19 9

输出

9 10 12 15 21 23 45 55 67 该数不存在 10 12 15 21 23 45 55 67

平衡二叉树: 

平衡二叉树的定义


平衡二叉排序树查找算法的性能取决于二叉树的结构,而二叉树的形状则取决于其数据集。
如果数据呈有序排列,则二叉排序树是线性的,查找的时间复杂度为O(n);反之,如果二叉排序
树的结构合理,则查找速度较快,查找的时间复杂度为O(logn)。事实上,树的高度越小,查找
速度越快。因此,希望二叉树的高度尽可能小。本节将讨论一种特殊类型的二叉排序树,称为平
衡二叉树
(Balanced Binary Tree 或 Height-Balanced Tree),因由前苏联数学家 Adelson-Velskii 和
Landis 提出,所以又称AVL树。


平衡二叉树或者是空树,或者是具有如下特征的二叉排序树:
(1)左子树和右子树的深度之差的绝对值不超过1;
(2)左子树和右子树也是平衡二叉树。


若将二叉树上结点的平衡因子(Balance Factor,BF)定义为该结点左子树和右子树的深度之
差,则平衡二叉树上所有结点的平衡因子只可能是-1、0和1。只要二叉树上有一个结点的平衡
因子的绝对值大于1,则该二叉树就是不平衡的。图7.11(a)所示为两棵平衡二叉树,而图 7.11
(b)所示为两棵不平衡的二叉树,结点中的值为该结点的平衡因子。

平衡二叉树的调整(重难点)

LL型调整操作由于在A左子树根结点的左子树上插入结点,A的平衡因子由1增至2,致使以A为根的子树失去平衡,则需进行一次向右的顺时针旋转操作 

RR 型调整操作:当在 A 的右子树的右子树上插入结点时,A 的平衡因子由 -1 变为 -2,导致以 A 为根结点的子树失去平衡。此时,需要进行一次向左的逆时针旋转操作,将 A 的右子树作为其左子树的右子树,并将 A 作为其左子树的根结点。

LR型调整操作:由于在A的左子树根结点的右子树上插入结点, A的平衡因子由1增至2,致使以A为根结点的子树失去平衡,则需进行两次旋转操作。第一次对B及其右子树进行递时针旋转,C转上去成为B的根,这时变成了LL型,所以第二次进行LL型的顺时针旋转即可恢复平衡。如果C原来有左子树,则调整C的左子树为B的右子树,


RL型调整操作:由于在A的右子树根结点的左子树上插入结点,A的平衡因子由-1变为-2,致使以A 为根结点的子树失去平衡,则旋转方法和LR型相对称,也需进行两次旋转,先顺时针右旋,再逆时针左旋。

左,右旋转调整代码:

 void Turnleft(TreeNode*& r) {
        TreeNode* A = r;
        TreeNode* B = r->right;
        A->right = B->left;
        B->left = A;
        r = B;
    }

    void Turnright(TreeNode*& r) {
        TreeNode* A = r;
        TreeNode* B = r->left;
        A->left = B->right;
        B->right = A;
        r = B;
    }

 判断不平衡类型类型的代码:

 

void fun1(vector<int>& g, TreeNode* r) {
        if ( r == NULL||(r->left==NULL&&r->right==NULL))return;
        if (mp[r->left] == mp[r->right])return;
        g.push_back(mp[r->left] - mp[r->right]);
        fun1(g, r->left);
        fun1(g, r->right);
    }

string check(TreeNode* root) {
        vector<int>g;
        fun1(g, root);
        if (g[0] == 2&&g[1]==1)return "LL";
        else if (g[0] == 2&&g[1]==-1)return "LR";
        else {
            if (g[0] == -2&&g[1]==1)return "RL";
            return "RR";
        }
        return "NO";
    }

将二叉树转换成平衡二叉树的代码:


class Solution {
public:
    unordered_map<TreeNode*, int>mp;

    void fun1(vector<int>& g, TreeNode* r) {
        if ( r == NULL||(r->left==NULL&&r->right==NULL))return;
        if (mp[r->left] == mp[r->right])return;
        g.push_back(mp[r->left] - mp[r->right]);
        fun1(g, r->left);
        fun1(g, r->right);
    }

    string check(TreeNode* root) {
        vector<int>g;
        fun1(g, root);
        if (g[0] == 2&&g[1]==1)return "LL";
        else if (g[0] == 2&&g[1]==-1)return "LR";
        else {
            if (g[0] == -2&&g[1]==1)return "RL";
            return "RR";
        }
        return "NO";
    }

    void Turnleft(TreeNode*& r) {
        TreeNode* A = r;
        TreeNode* B = r->right;
        A->right = B->left;
        B->left = A;
        r = B;
    }

    void Turnright(TreeNode*& r) {
        TreeNode* A = r;
        TreeNode* B = r->left;
        A->left = B->right;
        B->right = A;
        r = B;
    }

    void change(TreeNode*& r, string ret) {
        if (ret == "LL") {
            Turnright(r);
            mp[r] = mp[r->left] + 1;
        }
        else if (ret == "RR") {
            Turnleft(r);
            mp[r] = mp[r->left] + 1;
        }
        else if (ret == "RL") {
            Turnright(r->right);
            Turnleft(r);
            mp[r] = mp[r->left] + 1;
        }
        else {
            Turnleft(r->left);
            Turnright(r);
            mp[r] = mp[r->left] + 1;
        }
    }

    int dfs(TreeNode*& root) {
        if (root == NULL) {
            return 0;
        }
        int lh = dfs(root->left);
        int rh = dfs(root->right);

        int h = lh - rh;
        //cout << "__________________" << lh << " " << rh << " " << h << "______"<<root->val<<endl;
        if (h == 2 || h == -2) {
            //cout << root->val << endl;
            string ret = check(root);
            //cout << ret << endl;
            change(root, ret);
        }
        mp[root] = max(lh, rh) + 1;
        return max(lh,rh)+1;
    }

    TreeNode* balanceBST(TreeNode* root) {
        dfs(root);
        return root;
    }
};

 完整代码:

代码中有测试样例

#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<math.h>
#include<map>
#include<sstream>
#include<deque>
#include<unordered_map>
using namespace std;

// Definition for a binary tree node.
struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode() : val(0), left(nullptr), right(nullptr) {}
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
    TreeNode(int x, TreeNode* left, TreeNode* right) : val(x), left(left), right(right) {}
};

// Function to insert a value into BST
TreeNode* insertIntoBST(TreeNode* root, int val) {
    if (!root) {
        return new TreeNode(val);
    }
    if (val < root->val) {
        root->left = insertIntoBST(root->left, val);
    }
    else {
        root->right = insertIntoBST(root->right, val);
    }
    return root;
}

// Function to construct BST from preorder traversal
TreeNode* bstFromPreorder(vector<int>& preorder) {
    TreeNode* root = nullptr;
    for (int val : preorder) {
        if (val == 0)continue;
        root = insertIntoBST(root, val);
    }
    return root;
}

// Function to perform inorder traversal (for verification)
void inorderTraversal(TreeNode* root) {
    if (root) {
        inorderTraversal(root->left);
        cout << root->val << " ";
        inorderTraversal(root->right);
    }
}


// Function to perform level order traversal
void levelOrderTraversal(TreeNode* root) {
    if (!root) {
        return;
    }

    queue<TreeNode*> q;
    q.push(root);

    while (!q.empty()) {
        TreeNode* current = q.front();
        q.pop();

        cout << current->val << " ";

        if (current->left) {
            q.push(current->left);
        }
        if (current->right) {
            q.push(current->right);
        }
    }
}


class Solution {
public:
    unordered_map<TreeNode*, int>mp;

    void fun1(vector<int>& g, TreeNode* r) {
        if ( r == NULL||(r->left==NULL&&r->right==NULL))return;
        if (mp[r->left] == mp[r->right])return;
        g.push_back(mp[r->left] - mp[r->right]);
        fun1(g, r->left);
        fun1(g, r->right);
    }

    string check(TreeNode* root) {
        vector<int>g;
        fun1(g, root);
        if (g[0] == 2&&g[1]==1)return "LL";
        else if (g[0] == 2&&g[1]==-1)return "LR";
        else {
            if (g[0] == -2&&g[1]==1)return "RL";
            return "RR";
        }
        return "NO";
    }

    void Turnleft(TreeNode*& r) {
        TreeNode* A = r;
        TreeNode* B = r->right;
        A->right = B->left;
        B->left = A;
        r = B;
    }

    void Turnright(TreeNode*& r) {
        TreeNode* A = r;
        TreeNode* B = r->left;
        A->left = B->right;
        B->right = A;
        r = B;
    }

    void change(TreeNode*& r, string ret) {
        if (ret == "LL") {
            Turnright(r);
            mp[r] = mp[r->left] + 1;
        }
        else if (ret == "RR") {
            Turnleft(r);
            mp[r] = mp[r->left] + 1;
        }
        else if (ret == "RL") {
            Turnright(r->right);
            Turnleft(r);
            mp[r] = mp[r->left] + 1;
        }
        else {
            Turnleft(r->left);
            Turnright(r);
            mp[r] = mp[r->left] + 1;
        }
    }

    int dfs(TreeNode*& root) {
        if (root == NULL) {
            return 0;
        }
        int lh = dfs(root->left);
        int rh = dfs(root->right);

        int h = lh - rh;
        //cout << "__________________" << lh << " " << rh << " " << h << "______"<<root->val<<endl;
        if (h == 2 || h == -2) {
            //cout << root->val << endl;
            string ret = check(root);
            //cout << ret << endl;
            change(root, ret);
        }
        mp[root] = max(lh, rh) + 1;
        return max(lh,rh)+1;
    }

    TreeNode* balanceBST(TreeNode* root) {
        dfs(root);
        return root;
    }
};

int main() {
    vector<int> preorder={ 31,25,47,16,28,0,0,0,0,0,30,0,0 };

    /*
    31,25,47,0,0,40,69,0,43,0,0 ,0,0            RL
    1,0,2,0,3,0,4,0,0                         RR
    31,25,47,0,0,40,69,36,0,0,0 ,0,0            RL
    31,25,47,16,28,0,0,0,0,26,0,0,0             LR
    31,25,47,16,28,0,0,0,0,0,30,0,0             LR
    */

    TreeNode* root = bstFromPreorder(preorder);

    // Verification by performing inorder traversal
    inorderTraversal(root);
    cout << endl;
    levelOrderTraversal(root);
    cout << endl;

    Solution solve;
    root=solve.balanceBST(root);

    levelOrderTraversal(root);
    cout << endl;

    return 0;
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1347905.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

李宏毅 自然语言处理(Voice Conversion) 笔记

前一章笔记&#xff1a;李宏毅 自然语言处理&#xff08;Speech Recognition&#xff09; 笔记 引入 什么是voice conversion&#xff1f; 输入一段声音&#xff0c;输出另一段声音&#xff0c;我们希望这两端声音&#xff1a;内容一样&#xff0c;其他方面不一样&#xff08…

6个火爆全网的AI开源项目,用上月10万+

标题月10万可能说的有点夸张和含糊&#xff0c;10万具体指的是你可以利用这些开源项目实现&#xff1a; 访问量10万 收入10万 用户10万 …… 开源项目只是免费的工具&#xff0c;具体怎么实现还需要你根据自己需求去深入运营。这里只是给你推荐一些比较热门的开源项目&…

html-css-js移动端导航栏底部固定+i18n国际化全局

需求&#xff1a;要做一个移动端的仿照小程序的导航栏页面操作&#xff0c;但是这边加上了i18n国家化&#xff0c;由于页面切换的时候会导致国际化失效&#xff0c;所以写了这篇文章 1.效果 切换页面的时候中英文也会跟着改变&#xff0c;不会导致切换后回到默认的语言 2.实现…

【ESP-NOW with ESP32:向多个开发板发送数据(一对多)】

【ESP-NOW with ESP32&#xff1a;向多个开发板发送数据&#xff08;一对多&#xff09;】 1. 项目概况2. 先决条件2.1 环境配置2.2 所需零件 3. 获取主板 MAC 地址4. ESP32 发射器 &#xff08;ESP-NOW&#xff09;4.1 接收方的MAC地址4.2 OnDataSent&#xff08;&#xff09;…

2023-12-16 LeetCode每日一题(统计区间中的整数数目)

2023-12-16每日一题 一、题目编号 2276. 统计区间中的整数数目二、题目链接 点击跳转到题目位置 三、题目描述 给你区间的 空 集&#xff0c;请你设计并实现满足要求的数据结构&#xff1a; **新增&#xff1a;**添加一个区间到这个区间集合中。 **统计&#xff1a;**计算…

Plantuml之甘特图语法介绍(二十八)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

Transformer基本结构

Transformer基本结构 输入部分、编码部分、解码部分、输出部分 1、输入部分 原文本嵌入层及其位置编码器目标文本嵌入层及其位置编码器 位置编码器(PositionalEncoding)&#xff1a;将词汇位置不同可能会产生不同语义的信息加入到词张量中&#xff0c;以弥补位置信息的缺失 …

node版本管理器nvm的下载和使用

介绍 nvm 全名 node.js version management&#xff0c;顾名思义是一个nodejs的版本管理工具。通过它可以安装和切换不同版本的nodejs。 下载和安装 在下载和安装nvm前&#xff0c;需要确保当前电脑没有安装node&#xff0c;否则则需要先把原来的node卸载了。 下载地址&#…

HTML+CSS+JS制作三款雪花酷炫特效

🎀效果展示 🎀代码展示 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html

Fortran 编译后Dll依赖问题(libifcoremd.dll)

在VS里&#xff0c;点击运行按钮&#xff0c;程序正常运行。 在exe文件目录中&#xff0c;双击exe运行&#xff0c;提示缺少libifcoremd.dll文件&#xff0c;经查阅资料和以往的经验&#xff0c;解决方法如下&#xff1a; 红色是默认的&#xff0c;绿色是能够正常运行的。

AcWing算法提高课-2.3.1矩阵距离

算法提高课整理 CSDN个人主页&#xff1a;更好的阅读体验 本文同步发表于 CSDN | 洛谷 | AcWing | 个人博客 原题链接 题目描述 给定一个 01 矩阵&#xff0c;求矩阵中每个元素离 1 的最短曼哈顿距离。 输入格式 第一行两个整数 n , m n,m n,m。 接下来一个 n n n 行 …

跳圈圈^^

欢迎来到程序小院 跳圈圈 玩法&#xff1a;女骑士点击左下按钮越过低处火圈&#xff0c;点击右下按钮越过高处火圈&#xff0c;越过火圈获得分数&#xff0c;快去挑战吧^^。开始游戏https://www.ormcc.com/play/gameStart/235 html <div id"loadicon"><im…

机器学习分类模型

机器学习常见分类模型及特点 机器学习常见分类模型优缺点 决策树模型 决策树&#xff08;Decision Tree&#xff09;是一类常见的机器学习方法&#xff0c;可应用于分类与回归任务&#xff0c;这里主要讨论分类决策树。决策树是基于树结构来进行决策的。下图是使用决策树来决定…

python统计分析——协方差和pearson相关系数

参考资料&#xff1a;用python动手学统计学 使用数据见代码&#xff1a; dic{"x":[18.5,18.7,19.1,19.7,21.5,21.7,21.8,22.0,23.4,23.8],"y":[34,39,41,38,45,41,52,44,44,49] } cov_datapd.DataFrame(dic) 变量x、y的协方差Cov(x,y)的计算公式如下&am…

【LLM 】7个基本的NLP模型,为ML应用程序赋能

在上一篇文章中&#xff0c;我们已经解释了什么是NLP及其在现实世界中的应用。在这篇文章中&#xff0c;我们将继续介绍NLP应用程序中使用的一些主要深度学习模型。 BERT 来自变压器的双向编码器表示&#xff08;BERT&#xff09;由Jacob Devlin在2018年的论文《BERT:用于语言…

开关电源反馈环路重要参数设计,PC817和TL431实例计算和取值详解

author&#xff1a;小高霸气 data:2021.04.16 下面介绍开关电源重要的反馈电路PC817和TL431设计和应用。 在开关电源当中&#xff0c;对稳压反馈电路的设计通常会使用TL431和PC817来配合使用。在TOP 及3842等单端反激电路中的反馈电路很多都采用TL431和PC817作为参考、隔离、取…

css原子化的框架Tailwindcss的使用教程(原始html和vue项目的安装与配置)

安装教程 中文官网教程 原始的HTML里面使用 新建文件夹npm init -y 初始化项目 安装相关依赖 npm install -D tailwindcss postcss-cli autoprefixer初始化两个文件 npx tailwindcss init -p根目录下新建src/style.css tailwind base; tailwind components; tailwind ut…

Bmp2Png是什么工具?好用吗?

Bmp2Png是什么工具&#xff1f;好用吗&#xff1f; 批量BMP图片转为PNG透明图片&#xff0c;去掉BMP黑色背景&#xff0c;压缩导出png图片V1.1前段时间上传了一款bmp转png并去黑底的demo软件&#xff0c;非常受欢迎&#xff0c; 上一版本地址&#xff1a;批量BMP图片转为PNG…

Visual Transformer (ViT)模型详解

1 Vit简介 1.1 Vit的由来 ViT是2020年Google团队提出的将Transformer应用在图像分类的模型&#xff0c;虽然不是第一篇将transformer应用在视觉任务的论文&#xff0c;但是因为其模型“简单”且效果好&#xff0c;可扩展性强&#xff08;scalable&#xff0c;模型越大效果越好…

【LLM】人工智能应用构建的十大预训练NLP语言模型

在人工智能领域&#xff0c;自然语言处理&#xff08;NLP&#xff09;被广泛认为是阅读、破译、理解和理解人类语言的最重要工具。有了NLP&#xff0c;机器可以令人印象深刻地模仿人类的智力和能力&#xff0c;从文本预测到情感分析再到语音识别。 什么是自然语言处理&#xf…