23树(附自己写的源码)

23树

平衡二叉树虽然查找很快,但是做插入和删除的时候却很麻烦

所以要学习B+树,而要了解B+树,首先要学B树,而学B树之前,首先要学23树

        23树是如何在不影响查找效率的情况下,优化平衡二叉树的插入和删除

为什么叫23树:是因为它的树节点不一样,它的节点指针数量是不固定的(一般树是2个指针)

一般用的是2节点和3节点,如果遇到4节点(4节点只会临时存在)会变成3个2节点

准备几个数:

插入的时候一开始第一个数是2节点,当第二个数进来后变成3节点,当第三个数进来后变成4节点,然后4节点变成3个2节点。

然后第四个节点进来,首先将其沉底,第五个也是一样

然后继续插入:

然后因为4节点只是临时存在的,然后11升上去,而11的左边是5,右边是33,所以就会变成这个样子:

下面也是一样的,查找效率降低了一点点,但是增删效率增加的却不是那么一点点,再也不需要进行旋转:

但为什么不用23树,是因为23树的节点是固定的,就是2节点或3节点,数据多的时候也是很麻烦的,数据多的时候可能是希望4,5,6,7,8节点,这样层数不会更多(比较灵活)。

而一旦节点里面的指针数量是变化的就不叫23树,而是B树。

23树

  1. 有3种节点:2节点,3节点,4节点(临时)
  2. 4节点一旦出现进行拆分 从下往上

数据进入先往下沉,再往上升

以下是头文件:

#pragma once
#include<iostream>
using namespace std;

enum state{null_node,two_node,three_node,four_node};		//枚举表示空节点,2,3,4节点
template<class T>
struct TTTreeNode
{
	int		count;											//标记当前是空,2,3,4节点
	T		data[3];										//数据是数组  可以用vector动态数组(这个反而比较好)
	TTTreeNode*	pArr[4];									//存储指针的数组

	TTTreeNode()
	{
		count = null_node;
		memset(data, 0, sizeof(T) * 3);
		memset(pArr, 0, sizeof(TTTreeNode*) * 4);
	}
	
};



template<class T>
class twothreeTree
{
public:
	TTTreeNode<T>* pRoot;//指向根节点
public:
	twothreeTree() { pRoot = NULL; }
	~twothreeTree(){}

	void insertNode(const T& data);
private:
	void _insertNode(TTTreeNode<T>* node, TTTreeNode<T>* pParent,const T& data);

};

//public:
template<class T>
void twothreeTree<T>::insertNode(const T& data)
{
	if (pRoot)
	{
		_insertNode(pRoot, NULL, data);//pRoot的父为空
	}
	else//当前树为空树
	{
		pRoot = new TTTreeNode<T>;
		pRoot->data[0] = data;
		pRoot->count = two_node;//2节点
	}
}


//private
template<class T>
void twothreeTree<T>::_insertNode(TTTreeNode<T>* node, TTTreeNode<T>* pParent, const T& data)
{
	if (node->count==null_node)//如果当前节点为空
	{
		node->data[0] = data;
		node->count++;
		return;
	}
	if (node->count == two_node)//如果当前节点为2
	{
		if (data>node->data[0])//判断新数据是不是比本来的数据大 往右插入
		{
			if (node->pArr[1])//判断有没有孩子
			{
				_insertNode(node->pArr[1], node, data);//插入当前节点的右孩子
			}
			else//没有孩子
			{
				node->data[1] = data;
				node->count++;
			}
		}
		else// 往左插入
		{
			if (node->pArr[0])//判断有没有孩子
			{
				_insertNode(node->pArr[0], node, data);//插入当前节点的右孩子
			}
			else//没有孩子
			{
				//原来的数据右移
				node->data[1] = node->data[0];
				//新数据进入
				node->data[0] = data;
				//节点变化
				node->count++;
			}
		}
	}
	else//如果当前节点为3
	{
		if (data<node->data[0])//往最左边插入
		{
			if (node->pArr[0])//判断有没有孩子
			{
				_insertNode(node->pArr[0], node, data);//有孩子统一递归
			}
			else
			{
				//中间变右边
				node->data[2] = node->data[1];
				//左边变中间
				node->data[1] = node->data[0];
				//新数据进入
				node->data[0] = data;
				//节点加加
				node->count++;
			}
		}
		else if(data < node->data[1])//往中间插入
		{
			if (node->pArr[1])//判断有没有孩子
			{
				_insertNode(node->pArr[1], node, data);
			}
			else
			{
				//中间变右边
				node->data[2] = node->data[1];
				//新数据变中间
				node->data[1] = data;
				//节点加加
				node->count++;
			}
		}
		else//往右边插入
		{
			if (node->pArr[2])//判断有没有孩子
			{
				_insertNode(node->pArr[2], node, data);
			}
			else
			{
				//新数据变右边
				node->data[2] = data;
				//节点加加
				node->count++;
			}
		}
	}
	if (node->count == four_node)//如果当前节点为4
	{
		//创建2个节点
		TTTreeNode<T>* node1 = new TTTreeNode<T>;//左
		TTTreeNode<T>* node2 = new TTTreeNode<T>;//右
		//	node1是左边的
		node1->data[0] = node->data[0];
		node1->pArr[0] = node->pArr[0];
		node1->pArr[1] = node->pArr[1];
		node1->count = two_node;
		//node2是右边的
		node2->data[0] = node->data[2];
		node2->pArr[0] = node->pArr[2];
		node2->pArr[1] = node->pArr[3];
		node1->count = two_node;

		//临时存储中间值
		T temp = node->data[1];
		if (pParent)//当前节点有没有父节点
		{
			//找位置插入
			if (temp<pParent->data[0])//左边
			{
				if (pParent->pArr[2])//最右边有孩子
				{
					pParent->data[2] = pParent->data[1];
					pParent->data[1] = pParent->data[0];
					pParent->data[0] = temp;
					pParent->pArr[3] = pParent->pArr[2];
					pParent->pArr[2] = pParent->pArr[1];
					pParent->pArr[1] = node2;
					pParent->pArr[0] = node1;
				}
				else if(pParent->pArr[1])//最右边没孩子,中间有孩子
				{
					pParent->data[1] = pParent->data[0];
					pParent->data[0] = temp;
					pParent->pArr[2] = pParent->pArr[1];
					pParent->pArr[1] = node2;
					pParent->pArr[0] = node1;
				}
			}
			else if(pParent->count==two_node || (pParent->count>1) && (temp < pParent->data[1]))//中间
			{
				if (pParent->pArr[2])//最右边有孩子
				{
					pParent->data[2] = pParent->data[1];
					pParent->data[1] = temp;
					pParent->pArr[3] = pParent->pArr[2];
					pParent->pArr[2] = node2;
					pParent->pArr[1] = node1;
				}
				else if (pParent->pArr[1])//最右边没孩子,中间有孩子
				{
					pParent->data[1] = temp;
					pParent->pArr[2] = node2;
					pParent->pArr[1] = node1;
				}
			}
			else if(pParent->count == three_node || (pParent->count > 2) && (temp < pParent->data[2]))//右边
			{
				//父节点是3节点,直接向上升
				if (pParent->pArr[2])
				{
					pParent->data[2] = temp;
					pParent->pArr[3] = node2;
					pParent->pArr[2] = node1;
				}
			}
			pParent->count++;
			//释放内存
			delete node;

		}
		else
		{
			//当前节点变成二节点
			memset(node->data, 0, sizeof(T) * 3);//清空数组
			memset(node->pArr, 0, sizeof(TTTreeNode<T>) * 4);//清空指针
			node->data[0] = temp;
			node->count = two_node;
			//node1成为左孩子 node2成为右孩子
			node->pArr[0] = node1;
			node->pArr[1] = node2;
		}
	}
}


源文件:

#include "twothreeTree.h"
int main()
{
	int arr[10] = { 44,88,33,66,11,5,77,15,35,80 };
	twothreeTree<int> Tree;

	for (int i = 0; i < 10; i++)
	{
		Tree.insertNode(arr[i]);
	}
	while (1)
	{
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/q244645787/article/details/128356500
今日推荐