C++详细实现红黑树流程详解

目录
  • 红黑树的概念
  • 红黑树的性质
  • 红黑树的定义与树结构
  • 插入
  • 新增结点插入后维护红黑树性质的主逻辑
  • 旋转
  • 验证
  • 红黑树与AVl树的比较
  • 红黑树的应用

红黑树的概念

红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的

概念总结:

红黑树是二叉搜索树的升级,结点里面存放的成员col标记当前结点的颜色,它的最长路径最多是最短路径的二倍,红黑树通过各个结点着色方式的限制接近平衡二叉树,但是不同于AVL的是AVL是一颗高度平衡的二叉树,红黑树只是接近平衡

红黑树的性质

  • 每个结点不是红色就是黑色
  • 根节点是黑色的
  • 如果一个节点是红色的,则它的两个孩子结点是黑色的
  • 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均 包含相同数目的黑色结点
  • 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)

红黑树性质总结:

1、红黑树结点的颜色只能是红色或者黑色

2、红黑树根节点必须是黑色

3、红黑树并没有连续的红色结点

4、红黑树中从根到叶子的每一条路径都包含相同的黑色结点

5、叶子是黑色,表示空的位置

最长路径和最短路径概念:

最短路径:从根结点到叶子结点每一条路径的结点颜色都是黑色的不包含红色

最长路径:红黑交替,黑色结点和红色结点的个数相等

思考:为什么满足上面的性质,红黑树就能保证:其最长路径中节点个数不会超过最短路径节点个数的两倍?

假设结点个数为N,那么最短路径就是logN,最长路径就是2 * logN,所有并不存在最长路径超过最短路径2倍的情况

红黑树的定义与树结构

//枚举红黑颜色
enum colour
{
	RED,
	BLACK,
};
//定义红黑树结点结构
template<class K,class V>
struct RBTreeNode
{
	//构造
	RBTreeNode(const pair<K, V>& kv = {0,0})
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _kv(kv)
		,_col(BLACK)
	{ }
	//定义三叉链
	RBTreeNode<K, V>* _left; //左孩子
	RBTreeNode<K, V>* _right;//右孩子
	RBTreeNode<K, V>* _parent;  //父亲
	pair<K, V> _kv;  //pair对象
	//节点的颜色
	colour _col;  //定义枚举变量
};
//定义红黑树
template<class K, class V>
class RBTree
{
		typedef RBTreeNode<K, V> Node;
	public:
		//构造
		RBTree()
			:_root(nullptr)
		{}
	private:
		Node* _root;  //定义树的根节点
};

插入

插入过程类似搜索树的插入,重要的是维护红黑树的性质

pair<Node*, bool> Insert(const pair<K, V>& kv)
{
	if (!_root) //空树处理
	{
		_root = new Node(kv);
		_root->_col = BLACK;
		return { _root, true };
	}
	//二叉搜索树的插入逻辑
	Node* cur = _root, * parent = nullptr;
	while (cur)
	{
		if (cur->_kv.first < kv.first)//插入结点比当前结点大
		{
			parent = cur;
			cur = cur->_right;
		}
		else if (cur->_kv.first > kv.first) //插入结点比当前结点小
		{
			parent = cur;
			cur = cur->_left;
		}
		else
		{
			return { cur, false }; //插入失败
		}
	}
	cur = new Node(kv);
	cur->_col = RED;  //新增结点颜色默认设置为RED
	//判断插入结点是否在parent的左边或者右边
	if (parent->_kv.first > kv.first)  //左边
	{
		parent->_left = cur;
		cur->_parent = parent;
	}
	else     //右边
	{
		parent->_right = cur;
		cur->_parent = parent;
	}
	/* 红黑树性质处理:
		如果这棵树一开始是符合红黑树的性质,但在新增结点之后,
		导致失去了红黑树的性质,这里需要控制结点的颜色和限制
		每条路径上黑色结点的个数,以上情况都要处理
    */
	while (parent && parent->_col == RED) //父亲存在且父亲为红色
	{
		Node* grandfather = parent->_parent;  //祖父
		//父亲出现在祖父的左边需要考虑的情况
		if(parent == grandfather ->left)
		{
			//1、uncle存在,uncle为红色
			/*
			   如果parent和uncle都存在并且都为红色这是情况一,
			   需要将parent和uncle的颜色变成红色,祖父颜色变成黑色
			   更新cur、parent、grandfather、uncle 继续向上调整
			*/
			//2、uncle不存在
			/*  这里考虑两种旋转情况,直线单旋转,折线双旋
				/*
					cur出现在parent的左边 ,右单旋转
					经过右单旋后,parent去做树的根,祖父做为右子树
					//调节结点颜色
					parent->_col = BLACK;
					grandfather->_col = RED;
				*/
				/*
					cur出现在parent的右边,左右双旋
					经过双旋后,cur作为树的根,grandfather为右子树
					调节结点颜色
					cur->_col = BLACK;
					grandfather->_col = RED;
				*/
			*/
		}
		else  //父亲出现在祖父的右边
		{
			Node* uncle = grandfather->_left; //叔叔在左子树
			/*
			情况一:叔叔存在,且叔叔和父亲都是红色,那么就需要将父亲
			和叔叔结点的颜色变成黑色,再将祖父的颜色变成红色,
			继续向上调整,更新孩子、父亲、祖父、叔叔的位置
			*/
			/*
				情况二:叔叔不存在
				/*
				 	1、新增结点出现在父亲的右边,直线情况,左单旋处理
				 	旋转完后parent去做父亲的根,grandfather做父亲
				 	的左子树
							//调节颜色,根为黑,左右孩子为红
					2、新增结点出现在父亲的左边,会出现折现的情况,
					引发双旋,旋转完后,cur变成根,
					parent和grandfaher去做cur的左右孩子
						   //调节颜色,根结点为黑,左右孩子为红
				*/
			*/
		}
	}
	//如果父亲不存在为了保证根结点是黑色的,这里一定得将根结点处理为黑色
	_root->_col = BLACK;
}

新增结点插入后维护红黑树性质的主逻辑

//1、父亲一定存在的情况,叔叔存在/不存在 父亲叔叔结点颜色为红色
while (parent && parent->_col == RED) //父亲存在且父亲为红色
{
	Node* grandfather = parent->_parent;  //祖父
	//如果父亲和叔叔结点颜色都是红色
	if (parent == grandfather->_left)
	{
		Node* uncle = grandfather->_right;
		if (uncle && uncle->_col == RED)  //对应情况:uncle存在且为红
		{
			//处理:父亲和叔叔变成黑色,祖父变成红色,继续向上调整
			uncle->_col = parent->_col = BLACK;
			grandfather->_col = RED;
			//向上调整
			cur = grandfather;  //调整孩子
			parent = cur->_parent;//调整父亲
		}
		else   //uncle不存在,uncle存在且为黑
		{
			//直线情况(cur在parent的左边):只考虑单旋,以grandfather为旋转点进行右单旋转,
			//旋转完后将祖父的颜色变成红色,将父亲的颜色变成黑色
			if (parent->_left == cur)
			{
				RotateR(grandfather);
				parent->_col = BLACK;
				grandfather->_col = RED;
			}
			else  //parent->_right == cur
			{
				//折线情况(cur在parent的右边):这里会引发双旋
				RotateL(parent);  //以parent为旋转点进行左单旋
				RotateR(grandfather); //以grandfather为旋转点进行右单旋转
				//旋转完后cur会去做树的根,那么设置为黑色,
				//为了保证每条路径的黑色结点个数相同,grandfather结点颜色设置为红
				cur->_col = BLACK;
				grandfather->_col = RED;  //黑色	结点个数相同
			}
		}
	}
	else //父亲在右子树
	{
			Node* uncle = grandfather->_left; //叔叔在左子树
			if (uncle&& uncle->_col == RED)  //情况一处理:叔叔存在,且叔叔的颜色是红色的(包含了父亲的颜色是红色的情况)
			{
				//根据情况一处理即可:叔叔和父亲变黑,
				//祖父变红(目的是为了每条路径的黑色结点个数相同),继续向上
				cur = grandfather;  //孩子
				parent = cur->_parent;//父亲
			}
			else //叔叔不存在
			{
				if (cur == parent->_right)  //新增结点在父亲的右边,直线情况左单旋处理
				{
					//左单旋转,以grandfather为旋转点,旋转完后parent去做新的根,grandfather去做左子树
					RotateL(grandfather);
					//调节颜色
					grandfather->_col = RED;
					parent->_col = BLACK;
				}
				else //新增结点在父亲的左边,折线情况,引发双旋
				{
					//处理:以parenrt为旋转点做右单旋,再以grandfather为旋转点做左单旋
					RotateR(parent);  //右旋
					RotateL(grandfather); //左旋
					parent->_col = grandfather->_col = RED;
					cur->_col = BLACK;
				}
				break;
			}
		}
	_root->_col = BLACK;
}

拆解讨论:

以下只列举parent在grandfather左边的情况,而parent在grandfather右边的情况处理方式只是反过来的,读者可以自行画图,这里仅留参考代码

Node* uncle = grandfather->_right;
if (uncle && uncle->_col == RED)  //对应情况:uncle存在且为红
{
	//处理:父亲和叔叔变成黑色,祖父变成红色,继续向上调整
	uncle->_col = parent->_col = BLACK;
	grandfather->_col = RED;
	//向上调整
	cur = grandfather;  //调整孩子
	parent = cur->_parent;//调整父亲
}

else   //uncle不存在,uncle存在且为黑
{
	//直线情况(cur在parent的左边):只考虑单旋,以grandfather为旋转点进行右单旋转,
	//旋转完后将祖父的颜色变成红色,将父亲的颜色变成黑色
	if (parent->_left == cur)
	{
		RotateR(grandfather);
		parent->_col = BLACK;
		grandfather->_col = RED;
	}
	else  //parent->_right == cur
	{
		//双旋转
	}
}

//折线情况(cur在parent的右边):这里会引发双旋
RotateL(parent);  //以parent为旋转点进行左单旋
RotateR(grandfather); //以grandfather为旋转点进行右单旋转
//旋转完后cur会去做树的根,那么设置为黑色,
//为了保证每条路径的黑色结点个数相同,grandfather结点颜色设置为红
cur->_col = BLACK;
grandfather->_col = RED;

旋转

void RotateR(Node* parent) //右单旋
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;
		parent->_left = subLR;
		if (subLR) subLR->_parent = parent;  //防止subLR为nullptr
		subL->_right = parent;
		Node* parent_parent = parent->_parent; //指针备份
		parent->_parent = subL;
		if (_root == parent) //如果parent就是树的根
		{
			_root = subL;  //subL取代parent
			_root->_parent = nullptr;
		}
		else  //如果parent并不是树的根
		{
			if (parent_parent->_left == parent) parent->_left = subL;
			else parent_parent->_right = subL;
			subL->_parent = parent_parent; //subL去做parent_parent的孩子
		}
	}
	//左单旋
	void RotateL(Node* parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;
		parent->_right = subRL;
		if (subRL) subRL->_parent = parent;
		subR->_left = parent;
		Node* parent_parent = parent->_parent;
		parent->_parent = subR;
		if (_root == parent)
		{
			_root = subR;
			_root->_parent = nullptr;
		}
		else
		{
			if (parent_parent->_left == parent) parent_parent->_left = subR;
			else parent_parent->_right = subR;
			subR->_parent = parent_parent;
		}
	}

验证

/*
	红黑树的几点性质在于:
	1、根结点必须是红色的
	2、不会出现连续的红色结点
	3、所有路径的黑色结点个数是相同的
*/
bool _CheckBlance(Node* root, int isBlackNum, int count)
{
	if (!root)
	{
		if (isBlackNum != count)
		{
			printf("黑色结点个数不均等\n");
			return false;
		}
		return true; //遍历完整棵树,如果以上列举的非法情况都不存在就返回true
	}
	//检查是否出现连续的红色结点
	if (root->_col == RED && root->_parent->_col == RED)
	{
		printf("出现了连续的红色结点\n");
		return false;
	}
	//走前序遍历的过程中记录每一条路径黑色结点的个数
	if (root->_col == BLACK) count++;
	//递归左右子树
	return _CheckBlance(root->_left, isBlackNum, count) &&
			_CheckBlance(root->_right, isBlackNum, count);
}
//验证红黑树
bool CheckBlance()
{
	if (!_root) return true;  //树为null
	//根结点是黑色的
	if (_root->_col != BLACK)
	{
		printf("根结点不是黑色的\n");
		return false;
	}
	//每一条路径黑色结点的个数必须是相同的,
	int isBlcakNum = 0;
	Node* left = _root;
	while (left)
	{
		if (left->_col == BLACK) isBlcakNum++; // 统计某一条路径的所以黑色结点个数
		left = left->_left;
	}
	//检查连续的红色结点,检查每一条路径的黑色结点个数是否相等
	return _CheckBlance(_root, isBlcakNum ,0);
}

红黑树与AVl树的比较

红黑树与AVL树的比较

红黑树和AVL树都是高效的平衡二叉树,增删改查的

时间复杂度都是O( log n),红黑树不追求绝对平衡,其只需保证最长路径不超过最短路径的2倍,相对而言,降低了插入和旋转的次数,所以在经常进行增删的结构中性能比AVL树更优,而且红黑树实现比较简单,所以实际运用中红黑树更多。

红黑树的应用

  • C++ STL库 – map/set、mutil_map/mutil_set
  • Java 库
  • linux内核
  • 其他一些库

完整代码博主已经放在git上了,读者可以参考

红黑树实现.

到此这篇关于C++详细实现红黑树流程详解的文章就介绍到这了,更多相关C++红黑树内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++关于树的定义全面梳理

    目录 概念 树 树的叶子节点 节点的度 分支结点 树的度 树的高度 树的深度 二叉树 二叉树的特点 满二叉树 完全二叉树 二叉查找树 示例 代码实现 开发环境 运行结果 概念 本文以一个简单的树为例,如下图,来记录树的一些概念. 树 一种由n个节点组成的具有一定层次关系的有限数据集合.每个节点有0个或者n个子节点,有一个根节点(没有前驱只有后继),除根节点外每一个节点都有一个前驱,0个或多个后继. 树的叶子节点 只有一个前驱,没有后继的节点,为最外层的节点.叶子节点的度为0. 节点的度 节点拥有

  • C++数据结构之AVL树的实现

    目录 1.概念 (1)二叉搜索树的缺点 (2)定义节点 2.插入 (1)拆分 (2)找节点与插节点 (3)更新平衡因子与旋转 3.判断 4.完整代码及测试代码 完整代码 测试代码 1.概念 (1)二叉搜索树的缺点 要手撕AVL树,我们首先要知道什么是AVL树.AVL树是在二叉搜索树的基础之上改造的.当我们插入的是一个有序的序列的时候,二叉搜素树会使用一条直线来进行存储,这样并不利于查找. 当遇到这种情况的时候我们就需要对这棵树来进行调整.AVL树会通过旋转等操作,来规避这种情况.最终满足每一个节

  • C++链式二叉树深入分析

    目录 二叉树的结构和概念 二叉树的操作 前序遍历 中序遍历和后序遍历 二叉树的节点个数 求二叉树叶子结点个数 求二叉树的深度 在二叉树查找为X的结点 之前我们的重点学习二叉树都是完全二叉树,接下来我们来说下普通二叉树,普通的二叉树如果我们使用数组存储,那么会浪费相当多的空间的,所以我们选择链表存储,我们先再来复习下二叉树的结构吧. 二叉树的结构和概念 二叉树概念是: 1. 空树 2. 非空:根节点,根节点的左子树.根节点的右子树组成的. 从概念中可以看出,二叉树定义是递归式的. 我们就手动创建一

  • C++超详细实现二叉树的遍历

    目录 二叉树的遍历 前序遍历 中序遍历 后序遍历 层序遍历 二叉树的遍历 Q:什么是二叉树的遍历? A:二叉树的遍历是指从根结点出发,按照某种次序依次访问二叉树中所有结点,使得每个结点被访问一次,且仅被访问一次. Q:二叉树有几种遍历方法? A:二叉树的遍历方法可以有很多种,如果限制了从左到右的习惯方式,那么主要分为以下四种:先序遍历,中序遍历,后序遍历,层序遍历. 前序遍历 Q:什么是先序遍历 A:先序遍历就是先访问树的根节点,再访问树的左子节点,再访问右子节点.可以想象为,从一棵二叉树根节点

  • C++超详细讲解树与二叉树

    目录 树 树的定义 树的名词解释 树的表示 树的存储结构 二叉树的概念及结构 二叉树的概念 二叉树的性质 二叉树的存储结构 顺序存储结构 链式存储结构 树 树的定义 Q:什么是树 A:树是一种 非线性 的数据结构,它是由 n ( n>=0 )个有限结点组成一个具有层次关系的集合.把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的. Q:树有什么特点 有一个特殊的结点,称为根结点,根节点没有前驱结点. 除根节点外,其余结点被分成M(M>0)个互不相交的集合T1.T2.…….T

  • C++深入讲解哈夫曼树

    目录 哈夫曼树的基本概念 1)路径 2)路径长度 3)权 4)结点的带权路径长度 5)树的带权路径长度 6)哈夫曼树 哈夫曼树的构造算法 哈夫曼树的构造过程 哈夫曼树算法的实现 1)结点的存储结构 2)构建哈夫曼树 哈夫曼树的基本概念 Q:什么是哈夫曼树 A:哈夫曼树又称最优树,是一类带权路径长度最短的树.在正式了解哈夫曼树之前,我们需要了解一些概念. 1)路径 Q:什么是路径 A:从树中一个结点到另一个结点之间的分支构成这两个结点之间的路径. 2)路径长度 Q:什么是路径长度 A:路径上的分支

  • C++简单又轻松建立链式二叉树流程

    目录 递归建立二叉树 二叉树的结构体 二叉树初始化 先序遍历 中序遍历 后序遍历 具体例题 输入的格式 全部源码 总结 递归建立二叉树 二叉树的结构体 typedef struct Node { int data; Node* lchild; Node* rchild; }BiNode,*BiTree; 二叉树顾名思义最多只有两个子结点和一个数据域,既然是链式那么子结点定义为结点指针类型,数据域就可以根据需要设置了,可以是整型也可以是字符型. 二叉树初始化 BiTree createBiTree

  • C++深入细致探究二叉搜索树

    目录 1.二叉搜索树的概念 2.二叉搜索树的操作 二叉搜索树的查找 二叉搜索树的插入 二叉搜索树的删除 3.二叉搜索树的实现 4.二叉搜索树的性能分析 1.二叉搜索树的概念  二叉搜索树又称二叉排序树,它可以是一颗空树,亦可以是一颗具有如下性质的二叉树:   ①若根节点的左子树不为空,则左子树上的所有节点的值域都小于根节点的值   ②若根节点的右子树不为空,则右子树上的所有节点的值域都大于根节点的值   ③根节点的左右子树分别也是一颗二叉搜索树 例如下面的这棵二叉树就是一棵二叉搜索树: 注意:判

  • C++使用数组来实现哈夫曼树

    目录 写在前面 构造思想 算法设计 构造实例 理解代码 确定结构体 循环找出最小值 调用细节 调试试图 总结 写在前面 哈夫曼树又称最优二叉树,是一种带权路径长度最短的二叉树.所谓树的带权路径长度,就是树中所有的叶结点的权值乘上其到根结点的路径长度(若根结点为0层,叶结点到根结点的路径长度为叶结点的层数).树的路径长度是从树根到每一结点的路径长度之和,记为WPL=(W1*L1+W2*L2+W3*L3+...+Wn*Ln),N个权值Wi(i=1,2,...n)构成一棵有N个叶结点的二叉树,相应的叶

  • C++详细实现红黑树流程详解

    目录 红黑树的概念 红黑树的性质 红黑树的定义与树结构 插入 新增结点插入后维护红黑树性质的主逻辑 旋转 验证 红黑树与AVl树的比较 红黑树的应用 红黑树的概念 红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black. 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的 概念总结: 红黑树是二叉搜索树的升级,结点里面存放的成员col标记当前结点的颜色,它的最长路径最多是最短路径的二倍,红黑

  • 数据结构 红黑树的详解

    数据结构 红黑树的详解 红黑树是具有下列着色性质的二叉查找树: 1.每一个节点或者着红色,或者着黑色. 2.根是黑色的. 3.如果一个节点是红色的,那么它的子节点必须是黑色. 4.从一个节点到一个NULL指针的每一条路径必须包含相同数目的黑色节点. 下面是一棵红黑树. 1.自底向上插入 通常把新项作为树叶放到树中.如果我们把该项涂成黑色,那么违反条件4,因为将会建立一条更长的黑节点路径.因此这一项必须涂成红色.如果它的父节点是黑色的,插入完成.如果父节点是红色的,那么违反条件3.在这种情况下我们

  • 微信小程序支付及退款流程详解

    首先说明一下,微信小程序支付的主要逻辑集中在后端,前端只需携带支付所需的数据请求后端接口然后根据返回结果做相应成功失败处理即可.我在后端使用的是php,当然在这篇博客里我不打算贴一堆代码来说明支付的具体实现,而主要会侧重于整个支付的流程和一些细节方面的东西.所以使用其他后端语言的朋友有需要也是可以看一下的.很多时候开发的需求和相应问题的解决真的要跳出语言语法层面,去从系统和流程的角度考虑.好的,也不说什么废话了.进入正题. 一. 支付 支付主要分为几个步骤: 前端携带支付需要的数据(商品id,购

  • 基于PHP的微信公众号的开发流程详解

    微信公众号开发分傻瓜模式和开发者模式两种,前者不要考虑调用某些接口,只要根据后台提示傻瓜式操作即可,适用于非专业开发人员. 开发模式当然就是懂程序开发的人员使用的. 下面简单说一下微信公众号开发的简易流程,新手看看会有帮助,高手请一笑而过. 1.配置服务器: A.首先在本机建立如下结构的文件夹(这里是我自己的习惯,仅供参考) MMPN:总目录mro message public number 微信公众号 backup:备份目录,主要用于备份php文件,每次修改时将原稿备份到里面去. images

  • MySQL使用Xtrabackup备份流程详解

    01 背景 Xtrabackup是Percona公司开发的一款开源的MySQL热备份工具,之前的工作中也是经常使用,但是也仅仅是停留在使用的阶段,对于这个工具的细节,并没有做过多的研究,今天细细看了一下过程,还是有点收获的,写下来记录一下,有不对的地方,还请指正. Xtrabackup工具能够备份InnoDB,XtraDB和MyISAM的表,它支持Percona Server的所有版本,而且兼容MySQL,也兼容MariaDB,还支持一些高级的特性,例如流方式备份.压缩.加密.以及增量备份等等.

  • Android zygote启动流程详解

    对zygote的理解 在Android系统中,zygote是一个native进程,是所有应用进程的父进程.而zygote则是Linux系统用户空间的第一个进程--init进程,通过fork的方式创建并启动的. 作用 zygote进程在启动时,会创建一个Dalvik虚拟机实例,每次孵化新的应用进程时,都会将这个Dalvik虚拟机实例复制到新的应用程序进程里面,从而使得每个应用程序进程都有一个独立的Dalvik虚拟机实例. zygote进程的主要作用有两个: 启动SystemServer. 孵化应用

  • Android view绘制流程详解

    绘制流程 measure 流程测量出 View 的宽高尺寸. layout 流程确定 View 的位置及最终尺寸. draw 流程将 View 绘制在屏幕上. Measure 测量流程 系统是通过 MeasureSpec 测量 View 的,在了解测量过程之前一定要了解这个 MeasureSpec . MeasureSpec MeasureSpec 是一个 32 位的 int 值打包而来的,打包为 MeasureSpec 主要是为了避免过多的对象内存分配. 为了方便操作,MeasureSpec

  • SpringMvc框架的简介与执行流程详解

    目录 一.SpringMvc框架简介 1.Mvc设计理念 2.SpringMvc简介 二.SpringMvc执行流程 1.流程图解 2.步骤描述 3.核心组件 三.整合Spring框架配置 1.spring-mvc配置 2.Web.xml配置 3.测试接口 4.常用注解说明 四.常见参数映射 1.普通映射 2.指定参数名 3.数组参数 4.Map参数 5.包装参数 6.Rest风格参数 五.源代码地址 一.SpringMvc框架简介 1.Mvc设计理念 M:代表模型Model 模型就是数据,应用

  • C语言 小游戏打砖块实现流程详解

    始祖是美国英宝格公司(en:Atari Games,ja:アタリ (ゲーム))于1976年推出的街机游戏"Breakout"(en:Breakout),由该公司在1972年发行的"PONG"(en:PONG,ja:ポン (ゲーム),世界上第一款电子游戏,类似台球)改良而来.相较于其前作,一个人就可以玩与变化丰富这两项特点让Breakout相当卖座,使各家公司竞相模仿. 因为规则简单与游戏性,现在许多移动电话都有内建打砖块游戏,也有许多因特网小游戏版本,目前在网上可以

  • C++ 情怀游戏扫雷的实现流程详解

    扫雷最原始的版本可以追溯到1973年一款名为"方块"的游戏. 不久,"方块"被改写成了游戏"Rlogic".在"Rlogic"里,玩家的任务是作为美国海军陆战队队员,为指挥中心探出一条没有地雷的安全路线,如果路全被地雷堵死就算输.两年后,汤姆·安德森在"Rlogic"的基础上又编写出了游戏"地雷",由此奠定了现代扫雷游戏的雏形. 1981年,微软公司的罗伯特·杜尔和卡特·约翰逊两位工程师

随机推荐