我的创作纪念日

一、机缘

成为创作者的初衷是从学习C/C++语法与数据结构过程中获得的灵感。在日常学习和项目实践中,我发现这些知识既丰富又复杂,对初学者而言尤为困难。因此,我决定通过博客记录自己的学习过程、解决思路以及代码实现,帮助更多人在C/C++的学习中少走弯路。

在写作中,特别关注:

  1. 语法详解:如指针与引用、面向对象编程等关键概念的讲解。
  2. 数据结构实现:链表、栈、队列、树等核心结构的代码演示与优化。
  3. 算法应用:结合数据结构的实际场景,展示如何高效解决问题。

二、收获

  • 粉丝支持

    • 随着文章的发布,逐渐吸引了一群热爱C/C++的读者。通过他们的反馈和交流,不断提升创作能力。
    • 一些关键文章,如动态内存管理和二叉树遍历,获得了较高的阅读量和互动。
  • 技术提升

    • 深入学习C++高级特性,如STL(标准模板库)的使用和模板编程的优化,进一步加深了对语言的理解。
    • 通过总结和写作,将学习与实践中的知识体系化,大幅提升了逻辑思维和代码能力。
  • 人脉拓展

    • 与许多程序员建立了联系,他们的建议和讨论对我的技术成长起到了重要作用。
    • 参与了C++相关的在线社区和开源项目,开拓了视野。

三、日常

创作已经融入我的日常:

  • 学习与实践结合:在日常编码中,遇到有价值的知识点或问题时,会第一时间记录,并在博客中详细讲解。
  • 合理安排时间:通过设定清晰的目标和计划,将工作、学习与创作有机结合。例如,利用碎片时间阅读技术文档,晚上或周末总结成文。
  • 创作的意义:通过博客,我发现不仅可以帮自己总结知识,还能为读者提供清晰的解决方案,成就感十足。

四、成就

让我感到有所成就的代码其中之一就是AVL树旋转的逻辑:

#pragma once
#include <iostream>
#include <assert.h>
using namespace std;
 
template <class K,class V>
struct AVLTreeNode
{
	pair<K, V> _kv; //结点的每个元素类型是pair,搜索场景是key/value
	int _bf; //记录平衡因子,balance factor
 
	AVLTreeNode<K, V>* _left;
	AVLTreeNode<K, V>* _right;
	AVLTreeNode<K, V>* _parent; //需要父结点的指针,方便更新平衡因子
 
	//结点的构造函数
	AVLTreeNode(const pair<K, V>& kv)
		:_kv(kv)
		,_left(nullptr)
		,_right(nullptr)
		,_parent(nullptr)
		,_bf(0)  //新结点的平衡因子都是0(因为它的左右子树均为空树,高度都是0,相减也为0)
	{}
};
 
template <class K,class V>
class AVLTree
{
	typedef AVLTreeNode<K, V> Node;
public:
 
	//右单旋(左子树高度高于右子树),结合抽象图分析代码逻辑
	void RotateR(Node* parent) //parent就是旋转点
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;
		Node* pParent = parent->_parent; //记录parent->_parent修改前的内容
 
		parent->_left = subLR; //核心代码
		subL->_right = parent; //核心代码
 
		if(subLR)  //subLR可能为空,需要判断
			subLR->_parent = parent; //需要修改subLR的父结点指针
		parent->_parent = subL;
		
		//旋转点可能是整棵树的根结点,那么需要更新根
		if (parent == _root)
		{
			_root = subL;
			subL->_parent = nullptr;
		}
		//旋转点也可能是局部子树的根结点,那么需要进行链接操作
		else
		{
			if (pParent->_left == parent)
				pParent->_left = subL;
			else
				pParent->_right = subL;
 
			subL->_parent = pParent;
		}
 
		//至此,旋转逻辑完毕,接下来需要更新平衡因子
		subL->_bf = 0;
		parent->_bf = 0;
	}
 
	//左单旋(右子树高度高于左子树),结合抽象图分析代码逻辑
	void RotateL(Node* parent) //parent就是旋转点
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;
		Node* pParent = parent->_parent; //记录parent->_parent修改前的内容
 
		parent->_right = subRL; //核心代码
		subR->_left = parent; //核心代码
 
		if (subRL)  //subRL可能为空,需要判断
			subRL->_parent = parent; //需要修改subRL的父结点指针
		parent->_parent = subR;
 
		//旋转点可能是整棵树的根结点,那么需要更新根
		if (parent == _root)
		{
			_root = subR;
			subR->_parent = nullptr;
		}
		//旋转点也可能是局部子树的根结点,那么需要进行链接操作
		else
		{
			if (pParent->_left == parent)
				pParent->_left = subR;
			else
				pParent->_right = subR;
 
			subR->_parent = pParent;
		}
 
		//至此,旋转逻辑完毕,接下来需要更新平衡因子
		subR->_bf = 0;
		parent->_bf = 0;
	}
 
	//左右双旋,结合图例分析代码逻辑
	void RotateLR(Node* parent)
	{
		//因为单旋会调整平衡因子,所以需要提前记录,防止丢失
		Node* subL = parent->_left;
		Node* subLR = subL->_right;
		int bf = subLR->_bf;
 
		RotateL(parent->_left); //复用左单旋
		RotateR(parent); //复用右单旋
 
		//场景1
		if (bf == -1)
		{
			subLR->_bf = 0;
			subL->_bf = 0;
			parent->_bf = 1;
		}
		//场景2
		else if (bf == 1)
		{
			subLR->_bf = 0;
			subL->_bf = -1;
			parent->_bf = 0;
		}
		//场景3
		else if (bf == 0)
		{
			subLR->_bf = 0;
			subL->_bf = 0;
			parent->_bf = 0;
		}
		else
		{
			assert(false);//中断程序,说明平衡因子出现问题了,这时候就需要检查我们写的代码
		}
	}
 
	//右左双旋,结合图例分析代码逻辑
	void RotateRL(Node* parent)
	{
		//因为单旋会调整平衡因子,所以需要提前记录,防止丢失
		Node* subR = parent->_right;
		Node* subRL = subR->_left;
		int bf = subRL->_bf;
 
		RotateR(parent->_right);
		RotateL(parent);
 
		//场景1
		if (bf == -1)
		{
			subR->_bf = 1;
			subRL->_bf = 0;
			parent->_bf = 0;
		}
		//场景2
		else if (bf == 1)
		{
			subR->_bf = 0;
			subRL->_bf = 0;
			parent->_bf = -1;
		}
		//场景3
		else if (bf == 0)
		{
			subR->_bf = 0;
			subRL->_bf = 0;
			parent->_bf = 0;
		}
		else
		{
			assert(false);//中断程序,说明平衡因子出现问题了,这时候就需要检查我们写的代码
		}
	}
 
	bool Insert(const pair<K, V>& kv)
	{
		if (_root == nullptr)
		{
			_root = new Node(kv);  //根结点的_parent指针为nullptr
			return true;
		}
 
		Node* parent = nullptr; //注意这里的parent是结点的父结点,不是结点中指向父结点的指针
		Node* cur = _root;
		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 false;
			}
		}
 
		//插入新结点
		cur= new Node(kv); //创建新结点
		if (parent->_kv.first < kv.first) //比较的是key值,value值不参与比较
		{
			parent->_right = cur;
		}
		else
		{
			parent->_left = cur;
		}
		//链接父亲
		cur->_parent = parent;
 
		//插入结点结束后还要控制平衡
		//更新平衡因子,沿着cur和parent向上更新
		while (parent) //保证parent不为空,如果parent为空就更新结束了,此时cur就是根结点
		{
			if (cur == parent->_left) //parent的平衡因子需要--
				parent->_bf--;
			else					//parent的平衡因子需要++
				parent->_bf++;
 
			//对应更新停止的第一种情况
			if (parent->_bf == 0)
			{
				break;
			}
			//对应更新停止的第二种情况
			else if (parent->_bf == 1 || parent->_bf == -1)
			{
				cur = parent;
				parent = parent->_parent;
			}
			//对应更新停止的第三种情况,这里写else if而不写else是为了防止插入前不是AVL树的情况
			else if (parent->_bf == 2 || parent->_bf == -2)
			{
 
				//这里就需要写旋转的逻辑,旋转的部分我们单独讲解
				//...
				if (parent->_bf == -2 && cur->_bf == -1) //parent和cur都满足左边高右边低,右单旋
				{
					RotateR(parent);
				}
 
				else if (parent->_bf == 2 && cur->_bf == 1)//parent和cur都满足右边高左边低,左单旋
				{
					RotateL(parent);
				}
 
				else if (parent->_bf == -2 && cur->_bf == 1) //左右双旋
				{
					RotateLR(parent);
				}
 
				else if (parent->_bf == 2 && cur->_bf == -1) //右左双旋
				{
					RotateRL(parent);
				}
				else
				{
					assert(false);
				}	
				break;
			}
			else
			{
				assert(false);//如果插入前不是AVL树,就中断程序,说明平衡因子出现问题了,这时候就需要检查我们写的代码
			}
		}
		return true;  //控制平衡后,就插入成功了,放回true
	}
	void InOrder()
	{
		_InOrder(_root);
		cout << endl;
	}
 
	int Height()
	{
		return _Height(_root);
	}
 
	int Size()
	{
		return _Size(_root);
	}
 
	bool IsBalanceTree()
	{
		return _IsBalanceTree(_root);
	}
 
	Node* Find(const K& key)
	{
		Node* cur = _root;
		while (cur)
		{
			if (cur->_kv.first < key)
			{
				cur = cur->_right;
			}
			else if (cur->_kv.first > key)
			{
				cur = cur->_left;
			}
			else
			{
				return cur;
			}
		}
 
		return nullptr;
	}
 
private:
	void _InOrder(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}
 
		_InOrder(root->_left);
		cout << root->_kv.first << ":" << root->_kv.second << endl;
		_InOrder(root->_right);
	}
 
	int _Height(Node* root)
	{
		if (root == nullptr)
			return 0;
		int leftHeight = _Height(root->_left);
		int rightHeight = _Height(root->_right);
		return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
	}
 
	int _Size(Node* root)
	{
		if (root == nullptr)
			return 0;
 
		return _Size(root->_left) + _Size(root->_right) + 1;
	}
 
	bool _IsBalanceTree(Node* root)
	{
		// 空树也是AVL树
		if (nullptr == root)
			return true;
		// 计算pRoot结点的平衡因子:即pRoot左右子树的高度差
		int leftHeight = _Height(root->_left);
		int rightHeight = _Height(root->_right);
		int diff = rightHeight - leftHeight;
 
		// 如果计算出的平衡因子与pRoot的平衡因子不相等,或者
		// pRoot平衡因子的绝对值超过1,则一定不是AVL树
		if (abs(diff) >= 2)
		{
			cout << root->_kv.first << "高度差异常" << endl;
			return false;
		}
 
		if (root->_bf != diff)
		{
			cout << root->_kv.first << "平衡因子异常" << endl;
			return false;
		}
 
		// pRoot的左和右如果都是AVL树,则该树一定是AVL树
		return _IsBalanceTree(root->_left) && _IsBalanceTree(root->_right);
	}
private:
	Node* _root = nullptr; //只需记录树的根节点
};

五、憧憬

  1. 职业目标
    • 希望未来能成为一名算法工程师,专注于高效算法的设计与实现,并将编程能力应用到实际项目中。
  2. 创作规划
    • 持续更新高质量内容,深入讲解C++ STL应用、设计模式与多线程编程等话题。
    • 开展系列教程,比如“零基础学习C++”或“算法竞赛实战”,通过图文并茂的方式让更多人受益。
  3. 长期目标
    • 探索更多学习和分享的形式,比如制作视频教程、参与线下分享会,让技术创作产生更大的影响力。

通过不断努力,希望能够把技术与分享结合得更紧密,让创作成为推动技术进步的一部分。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值