学期课程《数据结构与算法》的一个实验,能力有限,以后会更加努力积淀自己.
资料参考:《AVL二叉平衡树C++实现》 http://wenku.baidu.com/view/a1203a23cc7931b765ce158e.html
2020.12: 回头看自己入门写过的代码, 或许是因为阅历和经验,好笑之余还有些感慨。
三个部分(类):
1. user.cpp / user.h //用户系统辨认用户的主要函数,因为相比于数组来说平衡树的结构更适合调用、查询、修改
2. face.cpp / face.h //dos界面的显示代码,避免主函数的冗长
3. LMS.cpp //主函数部分
-------------------------------------------------------------------------------------------------------------------------------------------------------
user.cpp
#include "stdafx.h"
#include "user.h"
#include<iostream>
#include<string>
#include<vector>
#include<fstream>
using namespace std;
TreeNode::TreeNode(string value,string secret)
{
usersecret=secret;
data=value;
leftPtr=rightPtr=0;
height=0; //一半在插入节点的时候会初始化新节点,而该节点一开始肯定被插入到叶出,而叶节点的高度为0;
}
string TreeNode::getData()
{
return data;
}
void Tree::putinto()
{
int t=1;
ifstream fin("user.txt");
string s;
int i=0;
while(getline(fin,s))
{
i++;
}
//cout<<i<<endl;
ifstream finu("user.txt");
string w;
while(finu>>w)
{
//cout<<w<<" ";
if(t%2==1)
{
name.push_back(w);//data(name)
}
if(t%2==0)
{
secret.push_back(w); //secret
//cout<<"haha"<<endl;
}
t++;
}
}
void Tree::writein() //修改后写入文本
{
//nodeptr.inOrederTraversal();
ofstream("user.txt").close();
ofstream f1("user.txt");
if(!f1) cout<<"打不开此文件"<<endl;
for(int h=0;h<name1.size();h++)
{
//cout<<"yes"<<endl;
f1<<name1[h]<<" "<<secret1[h]<<endl;
}
f1.close();
}
Tree::Tree()
{
rootTreeNode=0;
}
Tree::~Tree()
{
destroyHelper(rootTreeNode);
}
/*int Tree::max(int s1,int s2)
{
return s1>s2?s1:s2;
}*/
//===删除主函数===
void Tree ::deleteValue(string value)
{
if(rootTreeNode!=0)
deleteHelper1(rootTreeNode,value);
}
//===删除算法助手2===
string Tree ::deleteHelper2(TreeNode * &nodePtr,string value)
{
string retVal;
if(nodePtr->leftPtr!=0)
{
retVal=deleteHelper2(nodePtr->leftPtr,value);
if(high(nodePtr->rightPtr)-high(nodePtr->leftPtr)==2)
{
if(high(nodePtr->rightPtr->leftPtr)>high(nodePtr->rightPtr->rightPtr))
doubleRotateRight(nodePtr);
else
rotateRight(nodePtr);
}
if(high(nodePtr->leftPtr)>high(nodePtr->rightPtr)){nodePtr->height=high(nodePtr->leftPtr)+1;}
else{nodePtr->height=high(nodePtr->rightPtr)+1;}
//nodePtr->height=max(high(nodePtr->leftPtr),high(nodePtr->rightPtr))+1;
}
else
{
retVal=nodePtr->data;
TreeNode * temp=nodePtr;
nodePtr=nodePtr->rightPtr==0?0:nodePtr->rightPtr;
delete temp;
}
return retVal;
}
//=====删除算法助手1========
void Tree ::deleteHelper1(TreeNode * &nodePtr,string value)
{
if(nodePtr==0)//找不到该数值
{
cout<<endl<<"树内没有该值!";
return;
}
if(nodePtr->data<value)
{
deleteHelper1(nodePtr->rightPtr,value);
if(high(nodePtr->leftPtr)-high(nodePtr->rightPtr)==2)//由于在右边删除了一个节点出现不平衡(调用high函数监测)
{
if(high(nodePtr->leftPtr->rightPtr)>high(nodePtr->leftPtr->leftPtr))
doubleRotateLeft(nodePtr);
else
rotateLeft(nodePtr);//相等或者大于
}
}
else if(value<nodePtr->data)
{
deleteHelper1(nodePtr->leftPtr,value);
if(high(nodePtr->rightPtr)-high(nodePtr->leftPtr)==2)
{
if(high(nodePtr->rightPtr->leftPtr)>high(nodePtr->rightPtr->rightPtr))
doubleRotateRight(nodePtr);
else
rotateRight(nodePtr);
}
}
else
{
if(nodePtr->rightPtr==0)
{
TreeNode * temp=nodePtr;
nodePtr=nodePtr->leftPtr;
delete temp;
}
else if(nodePtr->leftPtr==0)
{
TreeNode * temp=nodePtr;
nodePtr=nodePtr->rightPtr;
delete temp;
}
else
{
nodePtr->data=deleteHelper2(nodePtr->rightPtr,value);
if(high(nodePtr->leftPtr)-high(nodePtr->rightPtr)==2)//由于在右边删除了一个节点出现不平衡
{
if(high(nodePtr->leftPtr->rightPtr)>high(nodePtr->leftPtr->leftPtr))
doubleRotateLeft(nodePtr);
else
rotateLeft(nodePtr);//相等或者大于
}
}
}
if(nodePtr!=0)
if(high(nodePtr->leftPtr)>high(nodePtr->rightPtr)){nodePtr->height=high(nodePtr->leftPtr)+1;}
else{nodePtr->height=high(nodePtr->rightPtr)+1;}
// nodePtr->height=max(high(nodePtr->leftPtr),high(nodePtr->rightPtr))+1;
}
void Tree::rotateLeft(TreeNode * &nodePtr)
{
TreeNode * temp=nodePtr->leftPtr;
nodePtr->leftPtr=temp->rightPtr;
if(high(nodePtr->leftPtr)>high(nodePtr->rightPtr)){nodePtr->height=high(nodePtr->leftPtr)+1;}
else{nodePtr->height=high(nodePtr->rightPtr)+1;}
//nodePtr->height=max(high(nodePtr->leftPtr),high(nodePtr->rightPtr))+1;
temp->rightPtr=nodePtr;
nodePtr=temp;
if(high(nodePtr->leftPtr)>high(nodePtr->rightPtr)){nodePtr->height=high(nodePtr->leftPtr)+1;}
else{nodePtr->height=high(nodePtr->rightPtr)+1;}
//nodePtr->height=max(high(nodePtr->leftPtr),high(nodePtr->rightPtr))+1;
}
void Tree::rotateRight(TreeNode * &nodePtr)
{
TreeNode * temp=nodePtr->rightPtr;
nodePtr->rightPtr=temp->leftPtr;
if(high(nodePtr->leftPtr)>high(nodePtr->rightPtr)){nodePtr->height=high(nodePtr->leftPtr)+1;}
else{nodePtr->height=high(nodePtr->rightPtr)+1;}
//nodePtr->height=max(high(nodePtr->leftPtr),high(nodePtr->rightPtr))+1;
temp->leftPtr=nodePtr;
nodePtr=temp;
if(high(nodePtr->leftPtr)>high(nodePtr->rightPtr)){nodePtr->height=high(nodePtr->leftPtr)+1;}
else{nodePtr->height=high(nodePtr->rightPtr)+1;}
//nodePtr->height=max(high(nodePtr->leftPtr),high(nodePtr->rightPtr))+1;
}
void Tree ::doubleRotateLeft(TreeNode * &nodePtr)
{
rotateRight(nodePtr->leftPtr);
rotateLeft(nodePtr);
}
void Tree ::doubleRotateRight(TreeNode * &nodePtr)
{
rotateLeft(nodePtr->rightPtr);
rotateRight(nodePtr);
}
//===树节点的高度监测算法===
int Tree ::high(TreeNode * nodePtr)
{
return nodePtr==0?-1:nodePtr->height;
}
//===查找树函数算法===
TreeNode * Tree ::treeSearch(string value)
{
return searchHelper(rootTreeNode,value);
}
TreeNode * Tree ::searchHelper(TreeNode * nodePtr,string value)//使用递归实现搜索
{
TreeNode * retPtr=0;
if(nodePtr==0)
return retPtr;
if(value<nodePtr->data)
return searchHelper(nodePtr->leftPtr,value);
if(value>nodePtr->data)
return searchHelper(nodePtr->rightPtr,value);
return nodePtr;//这种if的测试应该把最不可能的结果放在最后进行。
}
//===插入树元素===
void Tree ::insertTreeNode(string value,string secret)
{
insertHelper(rootTreeNode,value,secret);
}
void Tree ::insertHelper(TreeNode * &nodePtr,string value,string secret)
{
if(nodePtr==0)
nodePtr=new TreeNode (value,secret);
else
{
if(value<nodePtr->data)
{
insertHelper(nodePtr->leftPtr,value,secret);
if(high(nodePtr->leftPtr)-high(nodePtr->rightPtr)==2)//调整AVL数
{
if(value<nodePtr->leftPtr->data)
rotateLeft(nodePtr);
else
doubleRotateLeft(nodePtr);
}
}
else if(nodePtr->data<value)
{
insertHelper(nodePtr->rightPtr,value,secret);
if(high(nodePtr->rightPtr)-high(nodePtr->leftPtr)==2)
{
if(value<nodePtr->rightPtr->data)
doubleRotateRight(nodePtr);
else
rotateRight(nodePtr);
}
}
else //如果value==nodePtr->data;因为是重复,所以直接无视掉;(空操作;(提示重复的用户名或者是编号)
cout<<"rename"<<endl;
}
//更新高度
if(high(nodePtr->leftPtr)>high(nodePtr->rightPtr)){nodePtr->height=high(nodePtr->leftPtr)+1;}
else{nodePtr->height=high(nodePtr->rightPtr)+1;}
//nodePtr->height=max(high(nodePtr->leftPtr),high(nodePtr->rightPtr))+1;
}
//===中序遍历===
void Tree ::inOrederTraversal()
{
inHelper(rootTreeNode);
}
void Tree ::inHelper(TreeNode * nodePtr)
{
if(nodePtr==0)
return;
inHelper(nodePtr->leftPtr);
name1.push_back(nodePtr->data);
secret1.push_back(nodePtr->usersecret);
inHelper(nodePtr->rightPtr);
}
//===中序遍历输出用户信息===
void Tree ::inOrederTraversal1()
{
inHelper1(rootTreeNode);
}
void Tree ::inHelper1(TreeNode * nodePtr)
{
if(nodePtr==0)
return;
inHelper1(nodePtr->leftPtr);
cout<<" "<<nodePtr->data<<endl;
//secret1.push_back(nodePtr->usersecret);
inHelper1(nodePtr->rightPtr);
}
//===遍历整个树 用于AVL的虚函数===
void Tree ::destroyHelper(TreeNode * nodePtr)
{
if(nodePtr==0)
return;
destroyHelper(nodePtr->leftPtr);
destroyHelper(nodePtr->rightPtr);
delete nodePtr;
}
//===输出画图===
void Tree ::outputTree()
{
cout<<endl;
if(rootTreeNode!=0)
outputTreeHelper(rootTreeNode,0);
else
cout<<"树为空!!";
}
void Tree ::outputTreeHelper(TreeNode * nodePtr,int space)//space 表示输出该值之前要输出多少个空格
{
if(nodePtr!=0)
{
outputTreeHelper(nodePtr->rightPtr,space+5);//输出该值之前应该先输出该值得左子树,往下推进一层,所以空格数加5
for(int i=0;i<space;i++)//输出空格以构建层次
cout<<' ';
cout<<nodePtr->getData()<<endl;//输出数值外还要输出换行
outputTreeHelper(nodePtr->leftPtr,space+5);
}
}
user.h
#include "stdafx.h"
#include<iostream>
#include<string>
#include<vector>
#include<fstream>
using namespace std;
//====定义树节点====
class TreeNode
{
public:
TreeNode(string value,string secret);
string getData();
string usersecret;
string data;
int height; //节点的高度
TreeNode *leftPtr;
TreeNode *rightPtr;
};
//===AVL二叉平衡树======
class Tree
{
public:
vector<string> name;
vector<string> secret;
vector<string> name1;
vector<string> secret1;
void putinto(); //读取文本内的用户信息内容储存
void writein() ;//修改后写入文本
Tree();
~Tree();
TreeNode * treeSearch(string value);//搜索二叉树的值,并返回指向该值的指针,如果树内无该值,返回一个空指针
void outputTree();//形象地打印出树(图)
void insertTreeNode(string value,string secret);//插入数值(添加用户)
void inOrederTraversal();//中序遍历打印树(按序放入文本用户信息)
void inOrederTraversal1();
void deleteValue(string value);//删除节点(删除用户)
private:
//以下四个函数为插入节点后的旋转函数,以维持树的平衡
void rotateLeft(TreeNode * &);
void rotateRight(TreeNode * &);//必须改变该节点的指向,所以为引用
void doubleRotateLeft(TreeNode * &);
void doubleRotateRight(TreeNode * &);
//删除节点的两个辅助函数
void deleteHelper1(TreeNode * &,string value);
string deleteHelper2(TreeNode * &,string value);
//测量节点高度的函数
int high(TreeNode * );
//返回节点高度较大值的函数
//int max(int s1,int s2);
//为实现递归原理相应的函数
void outputTreeHelper(TreeNode *,int space);
void destroyHelper(TreeNode *);
TreeNode * searchHelper(TreeNode *,string value);
TreeNode * rootTreeNode;
void insertHelper(TreeNode * &,string value,string secret);
void inHelper(TreeNode *);
void inHelper1(TreeNode *);
};
TreeNode::TreeNode(string value,string secret);
string TreeNode::getData();
void Tree::putinto();
void Tree::writein() ;//修改后写入文本
Tree::Tree();
Tree::~Tree();
//int Tree::max(int s1,int s2);
//===删除函数===
void Tree ::deleteValue(string value);
string Tree ::deleteHelper2(TreeNode * &nodePtr,string value);
void Tree ::deleteHelper1(TreeNode * &nodePtr,string value);
void Tree::rotateLeft(TreeNode * &nodePtr);
void Tree::rotateRight(TreeNode * &nodePtr);
void Tree ::doubleRotateLeft(TreeNode * &nodePtr);
void Tree ::doubleRotateRight(TreeNode * &nodePtr);
int Tree ::high(TreeNode * nodePtr);
//===查找算法===
TreeNode * Tree ::treeSearch(string value);
TreeNode * Tree ::searchHelper(TreeNode * nodePtr,string value);//使用递归实现搜索
//===插入节点元素===
void Tree ::insertTreeNode(string value,string secret);
void Tree ::insertHelper(TreeNode * &nodePtr,string value,string secret);
//===中序遍历===
void Tree ::inOrederTraversal();
void Tree ::inHelper(TreeNode * nodePtr);
//===中序遍历输出用户信息===
void Tree ::inOrederTraversal1();
void Tree ::inHelper1(TreeNode * nodePtr);
//===遍历整个树 用于AVL的虚函数===
void Tree ::destroyHelper(TreeNode * nodePtr);
//===输出画图===
void Tree ::outputTree();
void Tree ::outputTreeHelper(TreeNode * nodePtr,int space);
face.h
void ZJM1();
void JM1();
void JM2(Tree p,string s);
face.cpp
#include "stdafx.h"
#include "windows.h"
#include "user.h"
#include "face.h"
#include<sstream>
#include<cstdlib>
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
using namespace std;
void ZJM1()
{
JM1();
}
void JM1()
{
TreeNode *y;
Tree p;
p.putinto();
for(int k=0;k<p.name.size();k++)
{
p.insertTreeNode(p.name[k],p.secret[k]);
}
cout<<"欢迎使用用户登录系统"<<endl;
cout<<"1.登录"<<endl;
cout<<"2.申请账号"<<endl;
cout<<" "<<endl;
cout<<"请输入对应选项选择命令:"<<endl;
string q; cin>>q;
if(q=="1" || q=="2")
{
int f; f=atoi(q.c_str());
switch(f)
{
case 1:
{
system("cls");
cout<<"请输入用户名:"<<endl;//这里有一个if-else语句判定用户存在
string s;
cin>>s;
if( p.treeSearch(s)!=NULL )
{
y=p.treeSearch(s);
cout<<"请输入密码:"<<endl;
string h;
cin>>h;
if(y->usersecret==h)
{
JM2(p,s);
}
else
{
cout<<"密码错误,返回登录界面";
system("cls");
JM1();
}
}
else
{
cout<<"用户不存在,返回登陆界面";
system("cls");
JM1();
}
}
case 2:
{
cout<<"Loading";
system("cls");
cout<<"请输入新用户名:"<<endl;
string mz;
cin>>mz;
if(p.treeSearch(mz)!=NULL)
{
cout<<"用户名已存在,返回主菜单"<<endl;
system("cls");
JM1();
}
else
{
cout<<"请输入新用户密码:"<<endl;
string see;
cin>>see;
p.insertTreeNode(mz,see);
p.inOrederTraversal();
p.writein();
cout<<"添加成功,返回主界面选择登录"<<endl;
system("cls");
JM1();
}
}
}
}
else
{
cout<<"输入有误,请输入对应功能选项"<<endl;
cout<<"返回主界面";
system("cls");
JM1();
}
}
void JM2(Tree p,string s)
{
system("cls");
TreeNode *y;
string str;
Tree pp;
str=s;
pp=p;
cout<<"请选择所需要的服务:"<<endl;
cout<<"1.更改用户密码"<<endl;
cout<<"2.添加新用户"<<endl;
cout<<"3.删除用户"<<endl;
cout<<"4.显示所有用户"<<endl;
cout<<"5.AVL树显示"<<endl;
cout<<"6.退出"<<endl;
cout<<" "<<endl;
string f;cin>>f;
if( f=="1" || f=="2" || f=="3" || f=="4" || f=="5" ||f=="6")
{
cout<<"Loading";
system("cls");
int ff; ff=atoi(f.c_str());
switch(ff)
{
case 1:
{
y=p.treeSearch(s);
cout<<"用户:"<<y->data<<endl;
cout<<"输入新密码:"<<endl;
string d;
cin>>d;
y->usersecret=d;
p.inOrederTraversal();
p.writein();
cout<<"修改成功,返回主界面";
Tree p1;
p1.putinto();
for(int k=0;k<p1.name.size();k++)
{
// cout<<"yes"<<endl;
p1.insertTreeNode(p1.name[k],p1.secret[k]);
}
system("cls");
JM2(p1,s);
}
case 2:
{
cout<<"请输入新用户名:"<<endl;
string na;
cin>>na;
if(p.treeSearch(na)!=NULL)
{
cout<<"用户名已经存在,返回主菜单"<<endl;
Tree p7;
p7.putinto();
for(int k=0;k<p7.name.size();k++)
{
// cout<<"yes"<<endl;
p7.insertTreeNode(p7.name[k],p7.secret[k]);
}
system("cls");
JM2(p7,s);
}
else
{
cout<<"请输入新用户密码:"<<endl;
string se;
cin>>se;
p.insertTreeNode(na,se);
p.inOrederTraversal();
p.writein();
cout<<"添加成功,返回主界面"<<endl;
Tree p2;
p2.putinto();
for(int k=0;k<p2.name.size();k++)
{
// cout<<"yes"<<endl;
p2.insertTreeNode(p2.name[k],p2.secret[k]);
}
system("cls");
JM2(p2,s);
}
}
case 3:
{
cout<<"请输入要删除的用户名:"<<endl;
string nam;
cin>>nam;
if(p.treeSearch(nam)!=NULL)
{
p.deleteValue(nam);
p.inOrederTraversal();
p.writein();
cout<<"删除成功"<<endl;
Tree p3;
p3.putinto();
for(int k=0;k<p3.name.size();k++)
{
// cout<<"yes"<<endl;
p3.insertTreeNode(p3.name[k],p3.secret[k]);
}
system("cls");
JM2(p3,s);
}
else
cout<<"要删除的用户不存在,返回主界面"<<endl;
Tree p4;
p4.putinto();
for(int k=0;k<p4.name.size();k++)
{
// cout<<"yes"<<endl;
p4.insertTreeNode(p4.name[k],p4.secret[k]);
}
system("cls");
JM2(p4,s);
}
case 4:
{
cout<<"所有用户名为:"<<endl;
p.inOrederTraversal1();
cout<<"输入任意数返回主界面"<<endl;
string e;cin>>e;
if(e=="a")
{
Tree p5;
p5.putinto();
for(int k=0;k<p5.name.size();k++)
{
// cout<<"yes"<<endl;
p5.insertTreeNode(p5.name[k],p5.secret[k]);
}
system("cls");
JM2(p5,s);
}
else
{
Tree p6;
p6.putinto();
for(int k=0;k<p6.name.size();k++)
{
// cout<<"yes"<<endl;
p6.insertTreeNode(p6.name[k],p6.secret[k]);
}
system("cls");
JM2(p6,s);
}
}
case 5:
{
cout<<"用户形成的AVL树:"<<endl;
p.outputTree();
cout<<"输入任意数返回主界面"<<endl;
string e;cin>>e;
if(e=="a")
{
Tree p8;
p8.putinto();
for(int k=0;k<p8.name.size();k++)
{
// cout<<"yes"<<endl;
p8.insertTreeNode(p8.name[k],p8.secret[k]);
}
system("cls");
JM2(p8,s);
}
else
{
Tree p9;
p9.putinto();
for(int k=0;k<p9.name.size();k++)
{
// cout<<"yes"<<endl;
p9.insertTreeNode(p9.name[k],p9.secret[k]);
}
system("cls");
JM2(p9,s);
}
}
case 6:
{
cout<<" "<<endl;
cout<<"===谢谢使用==="<<endl;
system("cls");
JM1();
}
}
}
else
{
cout<<"输入信息错误,返回主菜单请按照对应选项选择";
JM2(pp,s);
}
}
LMS.cpp
#include "stdafx.h"
#include "windows.h"
#include "user.h"
#include "face.h"
#include<iostream>
#include<sstream>
#include<cstdlib>
#include<string>
#include<vector>
#include<fstream>
using namespace std;
int main(int argc, char* argv[])
{
//printf("Hello World!\n");
ZJM1();
return 0;
}
代码实现时间为12年,用的当时还算流行的入门工具是VC++6.0
现在C++20了。很多特性都更新了,现在回头再看这些代码,水平确实太低。无论是数据结构还是算法的优化,不过对于一个刚接触代码的学生,已经可以了。所以我就不抽风重写了。