数据结构和算法(06)---二叉树(c++)

文章目录

  • 目录
    • 二叉树
      • 1.二叉树的基本概念
      • 2.二叉树的应用和时间复杂度
      • 3.二叉树的插入
      • 4.二叉树的查找
      • 5. 二叉树的遍历
      • 6.二叉树的删除
    • 二叉树的基本操作
      • 1.二叉树的基础操作
      • 2.代码实现
    • 创建二叉树和三种遍历二叉树的方法

目录

  • 数据结构:
    • 逻辑结构:数组,栈,队列,字符串,树,图
    • 存储结构:顺序存储,链式存储
  • C++常用的数据结构有:string , stack , queue , deque , vector , list , map , iterators.

二叉树

1.二叉树的基本概念

树是一些节点的集合,节点之间用边链接,节点之间不能有环路。上层的节点称为父节点,下层节点称为子节点。最上层的节点称为根节点。

二叉树是特殊的树。对于每个节点而言,与之直接相连的子节点不能超过两个(可以为0)。左边的子节点称为左子树,右边的子节点称为右子树。如下图就是一颗二叉树:
在这里插入图片描述
与树相关的一些概念:
**叶子节点:**没有任何子节点的节点称为叶子节点
深度:对于任意节点N,其深度指的是从根节点到N的唯一路径的长。根的深度为0。深度最深的叶子节点的深度为树的深度。可以理解为:树根是一个入口,离树根越远,就越深。如上图:A、B、C的深度为1,D、E的深度为2。
: 对于任意节点N,从N到一片树叶的最远路径的长为N的高度。(只可以从从上到下不能经过从下到上的节点。)树叶的高为0。树的高为根的高。如上图,根的高度为2。A的高度为1,其他节点高度为0。

2.二叉树的应用和时间复杂度

二叉树是一种常见的数据结构,常常用于查找,也运用于unix等常见操作系统的文件系统中。c++STL(标准模板库)中的set和map也使用二叉树中的红黑树实现。

  • 二叉树的查找思想基于:在二叉树中,对于任意节点N,左子树中的所有项的值不大于节点N中存储的值,右子树中的所有项的值不小于节点N中存储的值。如下图:
    在这里插入图片描述
    这样,在查找时,只需要不断比较需要查找的x与N的大小,若小于N中的值,只需要搜索左子树,若大于N中的值,只需要搜索右子树。这样每次就能缩小搜索的范围。经过证明,普通二叉树的平均时间复杂度是O(LogN)。

看到这里,我们发现其实二叉树的搜索思想和二分查找一致,每次不断的减少搜索范围。但是二者之间还是有区别的。

对于二分查找而言,每次的时间复杂度不会超过O(LogN)。但是对于二叉树,搜索时间的复杂度取决于树的形状。在最坏情况下可能达到O(N)。如下图,如果要找到10,则要查找5次。

在这里插入图片描述
那我们为什么还要使用二叉树而不直接使用二分查找来代替?

这是因为,二分查找一般基于数组,如果需要插入或删除数据,则会带来很大的开销。因为每次插入或者删除数据需要将改变节点之后的数据往后挪或者往前挪。但是对于二叉树而言,只需要改变一下指向下一个节点的指针就可以很方便的实现插入或者删除。而且一些特殊的二叉树如红黑树可以保证查找的最坏复杂度不超过O(LogN)。

所以,如果是对于静态数据,不需要改变的数据而言,采用数组存储,使用二分查找比较好。而对于动态数据,需要频繁插入或者删除数据的,采取二叉树存储是较好的。

3.二叉树的插入

思路:插入数据x,从根节点开始,不断比较节点与x的大小。若x小于节点,下一次比较x与节点的左子树,反之,比较x与节点的右子树。直到遇到一个空的节点,插入数据。(我们不考虑插入重复数据) 。如下图:
在这里插入图片描述
过程:比较4与7,4<7,再比较4与7的左子树6,4<6,比较4与6的左子树3,4>3,比较4与3的右子树,为空,插入4。

代码:

template< typename T>
void BinaryTree<T>::insert(const T &theElement, BinaryNode * &t ) {if ( nullptr == t ){  //如果插入的节点没有创建,则进行创建t = new BinaryNode (theElement);} else if ( theElement < t->element ) {  //如果插入的节点小于当前的节点,则继续搜索其左子树insert( theElement, t->leftNode );} else if ( theElement > t->element ) { //如果插入的节点大于当前的节点,则继续搜索其右子树insert ( theElement, t->rightNode );} else {//重复的数据不添加到树中  (找到节点后,直接插入到合适的位置)}
};

4.二叉树的查找

思路:与插入类似,不断比较插入值与节点的值。代码如下

template< typename T>
bool BinaryTree<T>::isFind(const T &theElement, BinaryNode * t ) const {if ( nullptr == t ){return false;} else if ( theElement < t->element ) {return isFind( theElement, t->leftNode );} else if ( theElement > t->element ) {return isFind ( theElement, t->rightNode );} else { //匹配return true;}
};

5. 二叉树的遍历

二叉树的遍历有三种方式:

  • 前序遍历(DLR):首先访问根结点。然后如果有子树,则对于左孩子也采用DLR的遍历规则。没有就忽略。然后如果有右子树,则对右子树也采用DRL的遍历规则。没有就忽略。
  • 中序遍历(LDR):首先访问根节点的左子树(对左子树也采用LDR),没有则忽略。再访问根节点。最后则对右子树也采用LDR的遍历规则,没有就忽略。
  • 后序遍历:首先访问根节点的左子树(对左子树也采用LRD),没有则忽略。再对右子树也采用LRD的遍历规则,没有就忽略。最后则对右子树也采用LRD的遍历规则,没有就忽略。

三种遍历方式其实是根据根节点的访问顺序命名的。根最先方位为前序,次之访问为中序遍历。最后访问为后序遍历。

在这里插入图片描述
使用递归实现
前序遍历:

template< typename T>
void BinaryTree<T>::preOrder( BinaryNode *bNode ) const {if( nullptr != bNode ) {std::cout << bNode->element << " " ;preOrder(bNode->leftNode);preOrder(bNode->rightNode);}};

中序遍历:

template< typename T>
void BinaryTree<T>::inOrder( BinaryNode *bNode ) const {if( nullptr != bNode ) {inOrder(bNode->leftNode);std::cout << bNode->element << " " ;inOrder(bNode->rightNode);}
};

后序遍历:

template< typename T>
void BinaryTree<T>::postOrder( BinaryNode *bNode ) const {postOrder(bNode->leftNode);postOrder(bNode->rightNode);std::cout << bNode->element << " " ;
};

6.二叉树的删除

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
代码

template< typename T>
void BinaryTree<T>::remove(const T &theElement, BinaryNode * &t ) {if( nullptr == t ) {return;} else {if ( theElement < t->element) {remove(t->leftNode);} else if ( theElement > t->element ) {remove (t->rightNode);} else if  (nullptr != t->leftNode && nullptr != t->rightNode ) {  //需要删除的节点两个儿子t->element = findMin(t->rightNode)->element;remove(t->element, t->rightNode);} else {BinaryNode * oldNode = t;t = ( nullptr!= t->leftNode) ? t->leftNode : t->rightNode;delete oldNode;}}
};
emplate< typename T>
typename BinaryTree<T>::BinaryNode * BinaryTree<T>::findMin(BinaryNode *bNode) const {if ( nullptr!= bNode) {while( nullptr != bNode->leftNode) {bNode = bNode->leftNode;}}return bNode;
}

二叉树的完整代码

二叉树的基本操作

1.二叉树的基础操作

  • 1.创建二叉树
  • 2.递归输出二叉树
    • 2.1递归先序输出
    • 2.2递归中序输出
    • 2.3递归后序输出
  • 3.非递归输出
    • 3.1非递归先序输出
    • 3.2非递归中序输出
    • 3.3非递归后序输出
  • 4.层次遍历二叉树
  • 5.求树高
  • 6.求树叶子节点
  • 7.按值查找对应节点,输出左孩子结点值和右孩子结点值
  • 8.计算所有节点数

2.代码实现

#include<iostream>
#include<string>
#include<stack>
#include<deque>
#include<fstream>
using namespace std;//const int MAX_N = 100;
//数据节点
class Node
{
public:char data;//数据class Node *lchild;//左节点class Node *rchild;//右节点
};//二叉树
class Tree
{
public:Tree(){}~Tree(){}//构建二叉树void Create(string name){ifstream readfile;string str;readfile.open(name);if (readfile.is_open()){getline(readfile, str);//读取一行}readfile.close();CreateNode(str);//构建二叉树}//先序遍历非递归算法void Disp(){if (t == NULL){return;}stack<Node *> m_stack;//定义栈m_stack.push(t);while (!m_stack.empty()){Node *p = m_stack.top();//赋值一份当前双亲节点cout << p->data << ends;m_stack.pop();if (p->rchild)//先存储右子树,确保先输出左子树{m_stack.push(p->rchild);}if (p->lchild)//后存储左子树{m_stack.push(p->lchild);}}}//非递归中序遍历二叉树void DispMid(){if (t == NULL){return;}Node *p = t;stack<Node *>m_stack;while (p != NULL || !m_stack.empty()){while (p != NULL)//一路直走至左下角{m_stack.push(p);p = p->lchild;}if (!m_stack.empty()){p = m_stack.top();//备份当前栈顶地址m_stack.pop();cout << p->data << ends;p = p->rchild;}}}//非递归后序遍历二叉树void DispBehid(){if (t == NULL){return;}Node *pre = NULL, *p = t;stack<Node *>m_stack;while (p != NULL || !m_stack.empty()){while (p != NULL)//一路直走至左下角{m_stack.push(p);p = p->lchild;}p = m_stack.top();//右子树为空或者已访问,输出当前节点if (p->rchild == NULL || p->rchild == pre){cout << p->data << ends;pre = p;//将当前结点地址赋值pre作为下一次判断标志,防止重复访问m_stack.pop();p = NULL;//p赋值空以便访问右子树}else{p = p->rchild;//访问子树的右子树}}}//层次遍历void level_display(){if (t == NULL){return;}deque<Node *>m_qu;//定义队列m_qu.push_back(t);//树根入队列while (!m_qu.empty()){Node *p = m_qu.front();//拷贝当前对头cout <<p->data << ends;//输出m_qu.pop_front();if (p->lchild)//左孩子入队列{m_qu.push_back(p->lchild);}if (p->rchild)//右孩子入队列{m_qu.push_back(p->rchild);}}}//递归先序遍历输出二叉树void display(){cout << "递归先序:";output(t);cout << endl;}//递归中序遍历输出二叉树void displayMid(){cout << "递归中序:";outputMid(t);cout << endl;}//递归后序遍历输出二叉树void displayBhind(){cout << "递归后序";outputBhind(t);cout << endl;}//二叉树高度void Height(){int height = get_height(t);cout << "Height: " << height << endl;}//输出叶子节点值void display_leaf(){cout << "Leaves: ";output_leaf(t);cout << endl;}//查找二叉树中值data域为elem的节点void find_node(char elem){Node *res = NULL;res = find_node(t, elem, res);if (res != NULL){cout << "nice." << endl;if (res->lchild){cout << "left child:";cout << leftchild(res)->data << endl;}if (res->rchild){cout << "right child:";cout << rightchild(res)->data << endl;}}else{cout << "NO." << endl;}}//计算节点数void nodes_count(){int sum;if (t == NULL)//若为空,则0个节点{sum = 0;}else{sum = node_count(t);cout << "Total Nodes:" << sum + 1 << endl;}}
private:Node *t;//构建二叉树void CreateNode(string str){stack<Node *> m_stack;Node *p;int k;while (str.length() != 0){//若当前为'(',将双亲节点推入栈,下一位存储的p值作为左节点处理if (str[0] == '('){m_stack.push(p); k = 1;}//为右括号则栈顶退出一位else if (str[0] == ')'){m_stack.pop();}//为',',则下一个字符作右节点处理else if (str[0] == ','){k = 2;}//存储值用作双亲结点else{p = (Node *)malloc(sizeof(Node));p->data = str[0];p->lchild = p->rchild = NULL;//树根为空时,将第一个节点作为树根并赋值给私有成员变量if (t == NULL){t = p;}//树根不为空else{if (k == 1)//作为左节点处理,将栈中双亲节点的左指针指向当前节点{m_stack.top()->lchild = p;}else//作为右节点处理{m_stack.top()->rchild = p;}}}//重构串,除去首字符,并将串长度减小1str.assign(str.substr(1, str.length() - 1));}}//递归先序遍历输出二叉树void output(Node *t){if (t != NULL)//当树根不为空时{cout << t->data;//输出if (t->lchild != NULL || t->rchild != NULL)//左/右结点不为空时递归到下一层{cout << "(";output(t->lchild);if (t->rchild != NULL)//当左节点遍历结束后,左节点递归返回一层,递归右节点{cout << ",";}output(t->rchild);cout << ")";}}}//递归中序遍历二叉树void outputMid(Node *t){if (t == NULL)//空则返回{return;}else{cout << "(";outputMid(t->lchild);//递归左孩子节点if (t->rchild != NULL){cout << ",";}cout << t->data;//输出outputMid(t->rchild);//递归右孩子结点cout << ")";}}//递归后序遍历输出二叉树void outputBhind(Node *t){if (!t)//空则返回{return;}else{cout << "(";outputBhind(t->lchild);//递归左孩子节点if (t->rchild != NULL){cout << ",";}outputBhind(t->rchild);//递归右孩子结点cout << t->data;//输出cout << ")";}}//求树高int get_height(Node *t){int leftheight, rightheight;if (t == NULL)//递归至不存在子节点时返回0{return 0;}else{leftheight = get_height(t->lchild);//递归求左子树高度rightheight = get_height(t->rchild);//递归其右子树高度return leftheight > rightheight ? leftheight+1 : rightheight+1;//递归返回时返回最大值}}//查找左节点Node *leftchild(Node *p){return p->lchild;}//查找右节点Node *rightchild(Node *p){return p->rchild;}//输出叶子节点void output_leaf(Node *t){if (t != NULL)//树根不为空时{//当前节点没有子节点时输出节点数据if (t->lchild == NULL&&t->rchild == NULL){cout << t->data << ends;}output_leaf(t->lchild);//递归左子树output_leaf(t->rchild);//递归右子树}}//查找二叉树中值data域为elem的节点Node * find_node(Node *t, char elem, Node *res = NULL){//Node *res = NULL;if (t == NULL)//若当前节点为空,则返回结束{return NULL;}else{if (t->data == elem)//若找到值,返回地址{//res = t;return t;}else{if (res == NULL)//若保存结果的指针不为空,则递归查找左节点{res = find_node(t->lchild, elem, res);}if (res == NULL)//若保存结果的指针不为空,且左节点为搜索到,则递归查找右节点{res = find_node(t->rchild, elem, res);}}return res;}}//计算节点数int node_count(Node *t){int lcount = 0, rcount = 0;if (t == NULL)//空则返回{return 0;}else{if (t->lchild != NULL)//遍历左孩子节点{lcount = node_count(t->lchild);lcount += 1;}if (t->rchild != NULL)//遍历右孩子节点{rcount = node_count(t->rchild);rcount += 1;}return lcount + rcount;//返回当前左右孩子节点数}}
};int main()
{Tree m_tree;m_tree.Create("data");m_tree.display();//递归先序输出m_tree.displayMid();//递归中序输出m_tree.displayBhind();//递归后序输出m_tree.Height();//树高m_tree.display_leaf();//叶子节点cout << "非递归先序:";//cout << "Fir:";m_tree.Disp();//非递归先序遍历cout << endl;cout << "非递归中序:";//cout << "Mid:";m_tree.DispMid();//非递归中序遍历cout << endl;cout << "非递归后序:";//cout << "Bac:";m_tree.DispBehid();//非递归后序遍历cout << endl;cout << "层次遍历:";m_tree.level_display();//层次遍历cout << endl;cout << "Input element:";char elem;cin >> elem;m_tree.find_node(elem);//按节点值查找m_tree.nodes_count();//计算节点数return 0;
}

在这里插入图片描述

创建二叉树和三种遍历二叉树的方法


#include<iostream>  
#include<fstream>   
#include<string.h>using namespace std;  //定义二叉树的结构体
typedef struct BTree{int val;struct BTree *left , *right;
}BTree; //二叉树类的实现 
class Tree{
public:Tree();~Tree();//其他操作方法BTree *create_node(int level,string pos);  void PreOrder(BTree *t);   //先序遍历   void InOrder(BTree *t);    //中序遍历   void PostOrder(BTree *t);  //后序遍历BTree* root; //定义根节点   
};BTree* Tree::create_node(int level,string pos){int data;BTree *node = new BTree;cout<<"please enter data:level"<<level<<" "<<pos<<endl;cin>>data;//若输入的数据为0,则把该结点的子结点置为空   if(data == 0)  {  return NULL;  }  node->val= data;    /*create_node()的    参数用于在给二叉树赋值时表明 现在赋值的是哪个结点*/   node->left = create_node(level+1,"left");  node->right= create_node(level+1,"right");             return node;
}void Tree::PreOrder(BTree *t)  
{  if(t)  {  cout<<t->val<<endl;;  PreOrder(t->left);  PreOrder(t->right);                }  
}   void Tree::InOrder(BTree *t)  
{  if(t)  {  InOrder(t->left);  cout<<t->val<<endl;;  InOrder(t->right);  }  
}  void Tree::PostOrder(BTree *t)  
{  if(t)  {  PostOrder(t->left);  PostOrder(t->right);  cout<<t->val<<endl;    }  
}  int main()  
{  Tree tree;  tree.root = tree.create_node(1,"root");  cout<<"Pre"<<endl;  tree.PreOrder(tree.root);  cout<<"In"<<endl;  tree.InOrder(tree.root);  cout<<"Post"<<endl;  tree.PreOrder(tree.root);     return 0;  
}  

输入:
7
4 10
3 5 8 12
输出:
在这里插入图片描述

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

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

相关文章

如何转载CSDN博客

前言 对于喜欢逛CSDN的人来说&#xff0c;看别人的博客确实能够对自己有不小的提高&#xff0c;有时候看到特别好的博客想转载下载&#xff0c;但是不能一个字一个字的敲了&#xff0c;这时候我们就想快速转载别人的博客&#xff0c;把别人的博客移到自己的空间里面&#xff0c…

CSDN写博客(字体颜色、大小)

markdown里面的标记语言可以使用标签对来实现对文本文字颜色大小信息的控制。下面给出几个实例&#xff1a; 黑体字示例 微软雅黑示例 华文彩云示例 color#00ffff size可以根据实际大小进行设置&#xff0c;一般不超过7。 红色字体CSDN 红色字体CSDN 使用十六进制颜色值 …

bose qc30 安静的城市是什么样子

使用感受 网友1&#xff08;20岁&#xff09;&#xff1a; 当你带着这个耳机听音乐的时候&#xff0c;有一种感觉&#xff0c;感觉这个世界都是你歌曲里的MV&#xff0c;这个枯燥乏味的世界都被赋予了你心中的那份情感&#xff0c;这种感觉&#xff0c;真的很棒 网友2&#…

DeepLearning.ai 提炼笔记(5-1)-- 循环神经网络

参考博客 Class 5: 序列模型Sequence Models Week 1: 循环神经网络RNN (Recurrent) 文章目录Class 5: 序列模型Sequence ModelsWeek 1: 循环神经网络RNN (Recurrent)目录序列模型-循环神经网络1.序列模型的应用2.数学符号3.循环神经网络模型传统标准的神经网络循环神经网络的…

常见人工智能比赛平台总结

目录1.kaggle比赛1.1 kaggle比赛是什么&#xff1f;1.2 为什么举办kaggle比赛&#xff1f;1.3 kaggle比赛形式是什么&#xff1f;1.4 kaggle比赛的奖励制度是什么&#xff1f;2.阿里天池比赛2.1 阿里天池比赛是什么&#xff1f;2.2 为什么举办阿里天池比赛&#xff1f;2.3 阿里…

机器学习模型评分总结(sklearn)

文章目录目录模型评估评价指标1.分类评价指标acc、recall、F1、混淆矩阵、分类综合报告1.准确率方式一&#xff1a;accuracy_score方式二&#xff1a;metrics2.召回率3.F1分数4.混淆矩阵5.分类报告6.kappa scoreROC1.ROC计算2.ROC曲线3.具体实例2.回归评价指标3.聚类评价指标1.…

kaggle (02) - 房价预测案例(进阶版)

房价预测案例&#xff08;进阶版&#xff09; 这是进阶版的notebook。主要是为了比较几种模型框架。所以前面的特征工程部分内容&#xff0c;我也并没有做任何改动&#xff0c;重点都在后面的模型建造section Step 1: 检视源数据集 import numpy as np import pandas as pd读…

《Head First设计模式》第二章笔记 观察者模式

背景 客户有一个WeatherData对象&#xff0c;负责追踪温度、湿度和气压等数据。现在客户给我们提了个需求&#xff0c;让我们利用WeatherData对象取得数据&#xff0c;并更新三个布告板&#xff1a;目前状况、气象统计和天气预报。 WeatherData对象提供了4个接口&#xff1a; …

《Head First设计模式》第三章笔记 装饰者模式

装饰者模式&#xff08;Decorator Pattern) *利用组合&#xff08;composition&#xff09;和委托&#xff08;delegation&#xff09;可以在运行时实现继承行为的效果&#xff0c;动态地给对象加上新的行为。 *利用继承扩展子类的行为&#xff0c;是在编译时静态决定的&#x…

机器学习中如何解决数据不平衡问题?

文章目录目录什么是数据不平衡问题&#xff1f;数据不平衡会造成什么影响&#xff1f;如何处理数据不平衡问题&#xff1f;1、重新采样训练集1.1随机欠抽样1.2.基于聚类的过采样2.使用K-fold交叉验证3.转化为一分类问题4.组合不同的重采样数据集5.用不同比例重新采样6.多模型Ba…

《Head First设计模式》第四章笔记 工厂模式

之前我们一直在使用new操作符&#xff0c;但是实例化这种行为并不应该总是公开的进行&#xff0c;而且初始化经常会造成耦合问题&#xff0c;工厂模式将摆脱这种复杂的依赖&#xff0c;本次内容包括简单工厂&#xff0c;工厂方法和抽象工厂三种情况。 1 2 3 4 5 6 Duck duck&a…

《Head First设计模式》第五章笔记-单件模式

单件模式 定义&#xff1a;确保一个类只有一个实例&#xff0c;并提供全局访问点。 编写格式&#xff1a; 1 2 3 4 5 6 public class MyClass{ private MyClass(){}//构造方法私有化 public static MyClass getInstance(){ //提供全局访问点 return new My…

《Head First设计模式》第六章笔记-命令模式

封装调用-命令模式 命令模式可将“动作的请求者”从“动作的执行者”对象中解耦。 本篇中将不再描述书中所引入的“巴斯特家电自动化公司”的遥控器控制案例&#xff0c;而使用简单易懂的餐厅案例。 在开始之前&#xff0c;让我们通过一个现实中的例子来了解命令模式。 理解…

一文读懂机器学习库graphLab

文章目录目录什么是graphlab为什么使用graphlab?如何安装graphlab?graphlab的简单使用。目录 什么是graphlab GraphLab 是由CMU&#xff08;卡内基梅隆大学&#xff09;的Select 实验室在2010 年提出的一个基于图像处理模型的开源图计算框架&#xff0c;框架使用C语言开发实…

《Head First设计模式》第七章-适配器模式、外观模式

适配器模式 适配器模式是什么&#xff0c;你一定不难理解&#xff0c;因为现实中到处都是。比如说&#xff1a; 如果你需要在欧洲国家使用美国制造的笔记本电脑&#xff0c;你可能需要使用一个交流电的适配器…… 当你不想改变现有的代码&#xff0c;解决接口不适配问题&#…

《Head First设计模式》第八章笔记-模板方法模式

模板方法模式 之前所学习的模式都是围绕着封装进行&#xff0c;如对象创建、方法调用、复杂接口的封装等&#xff0c;这次的模板方法模式将深入封装算法块&#xff0c;好让子类可以在任何时候都将自己挂接进运算里。 模板方法定义&#xff1a;模板方法模式在一个方法中定义一…

机器学习基础-吴恩达-coursera-(第一周学习笔记)----Introduction and Linear Regression

课程网址&#xff1a;https://www.coursera.org/learn/machine-learning Week 1 —— Introduction and Linear Regression 目录 Week 1 Introduction and Linear Regression目录一 介绍1-1 机器学习概念及应用1-2 机器学习分类 二 单变量的线性回归2-1 假设函数hypothesis2…

常见8种机器学习算法总结

简介 机器学习算法太多了&#xff0c;分类、回归、聚类、推荐、图像识别领域等等&#xff0c;要想找到一个合适算法真的不容易&#xff0c;所以在实际应用中&#xff0c;我们一般都是采用启发式学习方式来实验。通常最开始我们都会选择大家普遍认同的算法&#xff0c;诸如SVM&a…

redis——数据结构(字典、链表、字符串)

1 字符串 redis并未使用传统的c语言字符串表示&#xff0c;它自己构建了一种简单的动态字符串抽象类型。 在redis里&#xff0c;c语言字符串只会作为字符串字面量出现&#xff0c;用在无需修改的地方。 当需要一个可以被修改的字符串时&#xff0c;redis就会使用自己实现的S…

Hotspot虚拟机的对象

创建 Step1:类加载检查 虚拟机遇到一条 new 指令时&#xff0c;首先将去检查这个指令的参数是否能在常量池中定位到这个类的符号引用&#xff0c;并且检查这个符号引用代表的类是否已被加载过、解析和初始化过。如果没有&#xff0c;那必须先执行相应的类加载过程。 Step2:分…