C++ AVL树管理系统
C++ AVL树管理系统使用平衡二叉树AVL来进行写一个管理系统
- 没有平衡二叉树基础的同学可以先去了解一下,这里不多讲
- 这里说一下平衡二叉树的特点:AVL树中任何节点的两个子树的高度最大差别为1,想要了解更多可以先去学习
话不多说,直接上代码:
//**********************************头文件
#include <iostream> //标准输入输出流
#include <cstdlib> //system函数
#include <iomanip> //输出格式控制
#include <stack> //C++ STL中的 栈结构
using namespace std; //标准名称空间
//**************************************类声明、函数声明
//二叉平衡树
class AVLTree
{
public:
//学生信息
typedef struct Student
{
long long id;//学号
char sex[5];//性别
char name[20];//姓名
char grade[20];//班级
}Student;
//二叉树结点
typedef struct node
{
Student data;//学生信息
int height;//结点高度
struct node* lchild;//左子树
struct node* rchild;//右子树
}node;
public:
AVLTree();//空构造函数
~AVLTree();//析构函数
void Push(Student data);//插入
void Pop(Student data);//删除
void Show();//中序遍历
node* Search(Student data);//搜索数据
bool Empty();//是否为空
friend ostream& operator<<(ostream& os, Student& data);//输出流重载
friend bool operator>(Student& data1, Student& data2);//大于号重载
friend bool operator<(Student& data1, Student& data2);//小于号重载
friend bool operator!=(Student& data1, Student& data2);//不等号重载
friend bool operator==(Student& data1, Student& data2);//等号重载
private:
node* root;//根结点
int getHeight(node* target);//获取结点高度
void Adjust(stack<node*>& nodestack);//结点调整
node* LLrotate(node* cur);//左左旋转
node* RRrotate(node* cur);//右右旋转
node* LRrotate(node* cur);//左右旋转
node* RLrotate(node* cur);//右左旋转
};
//系统类
class System
{
public:
System() :input(0) {}//构造函数
void Main();//系统主进程
private:
void Menu();//菜单
void Push();//插入
void Pop();//删除
void Search();//查找
void Show();//浏览
void Message(const char* msg);//消息提示框
void HeadLine();//打印表头
int input;//用户的输入
AVLTree tree;//平衡二叉树结构 存储数据
};
//**************************************主函数
int main()
{
System sys;
sys.Main();
return 0;
}
//**************************************类实现、函数实现
//------------------------------System------------
//菜单
void System::Menu()
{
{
cout << "|------------------------------------------------|" << endl;
cout << "| 学籍管理系统 |" << endl;
cout << "|------------------------------------------------|" << endl;
cout << "| 1.添加学生信息 |" << endl;
cout << "| 2.查找学生信息 |" << endl;
cout << "| 3.浏览全部信息 |" << endl;
cout << "| 4.删除学生信息 |" << endl;
cout << "| 5.退出管理系统 |" << endl;
cout << "|------------------------------------------------|" << endl;
cout << " 请输入您的选择:";
}
}
//系统主进程
void System::Main()
{
while (1)//程序主循环
{
Menu();//打印菜单
cin >> input;
switch (input)
{
case 1://添加
Push();
break;
case 2://查找
Search();
break;
case 3://浏览
Show();
break;
case 4://删除
Pop();
break;
case 5://退出
Message("欢迎下次使用!");
return;//退出主进程
break;
default:
cin.clear();//重置输入流
cin.ignore(1024, '\n');//清空输入流
Message("输入格式有误!");
break;
}
system("pause");//按任意键继续
system("cls");//清屏
}
}
//插入学生
void System::Push()
{
Message("1.添加学生信息");
AVLTree::Student data = { 0 };
cout << "请输入学生学号:";
cin >> data.id;//输入学号
cout << "请输入学生姓名:";
cin >> data.name;//输入姓名
cout << "请输入学生性别:";
cin >> data.sex;//输入性别
cout << "请输入学生班级:";
cin >> data.grade;//输入班级
if (cin.fail())
{
cout << endl;
Message("输入格式错误!");
cin.clear();//重置输入流
cin.ignore(1024, '\n');//清空输入流
return;
}
tree.Push(data);//插入数据
Message("学生添加成功!");
}
//删除学生
void System::Pop()
{
Message("4.删除学生信息");
AVLTree::Student target = { 0 };
cout << "请输入需要删除的学生学号:";
cin >> target.id;//输入目标学生学号
if (cin.fail())
{
cout << endl;
Message("输入格式错误!");
cin.clear();//重置输入流
cin.ignore(1024, '\n');//清空输入流
return;
}
AVLTree::node* result = tree.Search(target);//接收查找到的数据
if (result == nullptr)//未找到
{
Message("该学生不存在!");
return;
}
HeadLine();//打印表头
cout << result->data;//提示信息
tree.Pop(target);//删除学生
cout << endl;
Message("学生删除成功!");
}
//查找学生
void System::Search()
{
Message("2.查找学生信息");
AVLTree::Student target = { 0 };
cout << "请输入学生学号:";
cin >> target.id;//输入目标学生学号
if (cin.fail())
{
cout << endl;
Message("输入格式错误!");
cin.clear();//重置输入流
cin.ignore(1024, '\n');//清空输入流
return;
}
AVLTree::node* result = tree.Search(target);//接收查找结果
if (result == nullptr)//未找到学生
{
Message("未找到该学生!");
return;
}
else//找到学生
{
//打印数据
HeadLine();//打印表头
cout << result->data << endl;
}
}
//浏览学生
void System::Show()
{
Message("3.浏览全部信息");
if (tree.Empty())
{
Message("没有学生信息!");
return;
}
HeadLine();//打印表头
tree.Show();//打印数据
}
//消息提示框
void System::Message(const char* msg)
{
cout << "|-----------------" << msg << "-----------------|" << endl;
}
//打印表头
void System::HeadLine()
{
cout << "|------------|--------|----|---------------------|" << endl
<< std::left
<< setw(13) << "| 学号" << setw(9) << "| 姓名"
<< setw(5) << "|性别" << setw(21) << "| 班级 |"
<< endl
<< "|------------|--------|----|---------------------|" << endl;
}
//------------------------------AVLTree-----------
//空构造函数
AVLTree::AVLTree()
{
root = nullptr;
}
//析构函数
AVLTree::~AVLTree()
{
if (root == nullptr)//空树
return;//退出函数
stack<node*> nodestack;
node* cur = root;
nodestack.push(cur);
while (!nodestack.empty())
{
cur = nodestack.top();//获取栈顶元素
nodestack.pop();//出栈
if (cur->lchild != nullptr)
nodestack.push(cur->lchild);//左子树不为空则入栈
if (cur->rchild != nullptr)
nodestack.push(cur->rchild);//右子树不为空则入栈
delete cur;
cur = nullptr;
}
}
//插入
void AVLTree::Push(Student data)
{
if (root == nullptr)//空树
{
root = new node;
if (root == nullptr)//创建结点失败
return;
root->data = data;
root->height = 1;//根结点高度为1
root->lchild = nullptr;
root->rchild = nullptr;
}
else//非空树
{
node* cur = root;
stack<node*> nodestack;
while (cur != nullptr)
{
nodestack.push(cur);//记录路径
if (data > cur->data)//学号大 向右走
cur = cur->rchild;
else if (data < cur->data)//学号小 向左走
cur = cur->lchild;
else
return;//数据相等 退出函数
}
cur = nodestack.top();//获取栈顶元素
nodestack.pop();//出栈
node* newnode = new node;//创建新结点
if (newnode == nullptr)//结点创建失败
return;
newnode->data = data;//数据迁移
newnode->height = 1;//新结点的高度为1
newnode->rchild = nullptr;//左右子树置为空
newnode->lchild = nullptr;
if (data > cur->data)//将新结点连接至树上
cur->rchild = newnode;
else if (data < cur->data)
cur->lchild = newnode;
cur->height = max(getHeight(cur->lchild), getHeight(cur->rchild)) + 1;//重置当前结点高度
Adjust(nodestack);//沿路径调整
}
}
//删除
void AVLTree::Pop(Student data)
{
if (root == nullptr)//空树
return;
node* cur = root;
stack<node*> nodestack;//创建结点栈 记录路径
while (cur->data != data)
{
nodestack.push(cur);//记录路径
if (data > cur->data)
{
if (cur->rchild != nullptr)
cur = cur->rchild;
else
return;//未找到
}
else if (data < cur->data)
{
if (cur->lchild != nullptr)
cur = cur->lchild;
else
return;//未找到
}
}
//找到了
if (cur->lchild == nullptr && cur->rchild == nullptr)//叶子结点
{
if (nodestack.empty())//栈为空 说明是根结点
{
delete root;
root = nullptr;
return;
}
node* parent = nodestack.top();//获取栈顶元素
if (parent->lchild == cur)
parent->lchild = nullptr;
else if (parent->rchild == cur)
parent->rchild = nullptr;
delete cur;//删除结点
}
else if (cur->lchild == nullptr || cur->rchild == nullptr)//其中一颗子树为空
{
if (cur->lchild == nullptr)//左子树为空
{
if (nodestack.empty())//栈为空 说明是根结点
{
root = cur->rchild;//更结点变更
delete cur;//删除结点
return;//退出函数
}
node* parent = nodestack.top();//获取栈顶元素 父结点
if (parent->lchild == cur)
parent->lchild = cur->rchild;//断开连接
else if (parent->rchild == cur)
parent->rchild = cur->rchild;
delete cur;//删除结点
}
else if (cur->rchild == nullptr)//右子树为空
{
if (nodestack.empty())//栈为空 说明是根结点
{
root = cur->lchild;
delete cur;
return;
}
node* parent = nodestack.top();
if (parent->lchild == cur)
parent->lchild = cur->lchild;
else if (parent->rchild == cur)
parent->rchild = cur->lchild;
delete cur;//删除结点
}
}
else//两颗子树都存在的情况
{
nodestack.push(cur);//当前结点入栈 记录路径
node* precursor = cur->lchild;//寻找前驱结点
node* pre = cur;//前驱结点父结点
if (cur->lchild->rchild == nullptr)//前驱结点在子树上
{
cur->data = precursor->data;//数据迁移
cur->lchild = precursor->lchild;//断开连接
delete precursor;//删除结点
cur->height = max(getHeight(cur->lchild), getHeight(cur->rchild)) + 1;//重新计算结点高度
}
else//前驱结点不在子树上
{
while (precursor->rchild != nullptr)
{
nodestack.push(precursor);//放入栈 记录路径
pre = precursor;//记录前驱结点父结点
precursor = precursor->rchild;//前驱结点向右移动
}
cur->data = precursor->data;//数据迁移
pre->rchild = nullptr;//断开连接
delete precursor;//删除结点
}
}
Adjust(nodestack);//沿路径回栈调整结点
}
//中序遍历 数据升序
void AVLTree::Show()
{
if (root == nullptr)
return;
stack<node*> nodestack;
node* cur = root;
while (cur != nullptr || !nodestack.empty())
{
while (cur != nullptr)
{
nodestack.push(cur);
cur = cur->lchild;
}
if (!nodestack.empty())
{
cur = nodestack.top();
nodestack.pop();
cout << cur->data << endl;
cur = cur->rchild;
}
}
}
//查找数据
AVLTree::node* AVLTree::Search(Student data)
{
node* cur = root;
while (cur != nullptr)
{
if (cur->data == data)//学号匹配 返回数据
return cur;
else if (data > cur->data)
cur = cur->rchild;
else if (data < cur->data)
cur = cur->lchild;
}
return nullptr;//没找到
}
//是否为空
bool AVLTree::Empty()
{
return root == nullptr;
}
//获取结点高度
int AVLTree::getHeight(node* target)
{
if (target == nullptr)//空结点
return 0;
else
return target->height;
}
//沿路径调整结点
void AVLTree::Adjust(stack<node*>& nodestack)
{
node* result = nullptr;//调整结果
node* cur = nullptr;
while (!nodestack.empty())
{
cur = nodestack.top();//获取栈顶元素
nodestack.pop();//出栈
cur->height = max(getHeight(cur->lchild), getHeight(cur->rchild)) + 1;//调整高度
if (abs(getHeight(cur->lchild) - getHeight(cur->rchild)) >= 2)//平衡因子大于2 需要调整
{
if (getHeight(cur->lchild) > getHeight(cur->rchild))//左子树大于右子树
{
if (getHeight(cur->lchild->lchild) > getHeight(cur->lchild->rchild))//LL旋转
result = LLrotate(cur);
else if (getHeight(cur->lchild->lchild) < getHeight(cur->lchild->rchild))//LR旋转
result = LRrotate(cur);
}
else if (getHeight(cur->lchild) < getHeight(cur->rchild))//右子树大于左子树
{
if (getHeight(cur->lchild->lchild) > getHeight(cur->lchild->rchild))//RL旋转
result = RLrotate(cur);
else if (getHeight(cur->lchild->lchild) < getHeight(cur->lchild->rchild))//RR旋转
result = RRrotate(cur);
}
//将调整结果连接至树中
if (nodestack.empty())//路径为空 没有父结点
root = result;
else if (nodestack.top()->lchild == cur)//连接至左子树
nodestack.top()->lchild = result;
else if (nodestack.top()->rchild == cur)//连接至右子树
nodestack.top()->rchild = result;
}
}
}
//LL旋转
AVLTree::node* AVLTree::LLrotate(node* cur)
{
//旋转
node* curLeft = cur->lchild;
cur->lchild = curLeft->rchild;
curLeft->rchild = cur;
//高度调整
cur->height = max(getHeight(cur->lchild), getHeight(cur->rchild)) + 1;
curLeft->height = max(getHeight(curLeft->lchild), getHeight(curLeft->rchild)) + 1;
//返回子树根结点
return curLeft;
}
//RR旋转
AVLTree::node* AVLTree::RRrotate(node* cur)
{
//旋转
node* curRight = cur->rchild;
cur->rchild = curRight->lchild;
curRight->lchild = cur;
//高度调整
cur->height = max(getHeight(cur->lchild), getHeight(cur->rchild)) + 1;
curRight->height = max(getHeight(curRight->lchild), getHeight(curRight->rchild)) + 1;
//返回子树根结点
return curRight;
}
//LR旋转
AVLTree::node* AVLTree::LRrotate(node* cur)
{
cur->lchild = RRrotate(cur->lchild);
return LLrotate(cur);
}
//RL旋转
AVLTree::node* AVLTree::RLrotate(node* cur)
{
cur->rchild = LLrotate(cur->rchild);
return RRrotate(cur);
}
//------------------------------运算符重载---------
//输出流重载
ostream& operator<<(ostream& os, AVLTree::Student& data)
{
return os << std::left
<< '|' << setw(12) << data.id << '|' << setw(8) << data.name
<< '|' << setw(4) << data.sex << '|' << setw(21) << data.grade
<< '|' << endl
<< "|------------|--------|----|---------------------|";
}
//大于号重载
bool operator>(AVLTree::Student& data1, AVLTree::Student& data2)
{
return data1.id > data2.id;
}
//小于号重载
bool operator<(AVLTree::Student& data1, AVLTree::Student& data2)
{
return data1.id < data2.id;
}
//不等号重载
bool operator!=(AVLTree::Student& data1, AVLTree::Student& data2)
{
return data1.id != data2.id;
}
//等号重载
bool operator==(AVLTree::Student& data1, AVLTree::Student& data2)
{
return data1.id == data2.id;
}
运行效果如下: