c++用户管理信息(单链表管理)

类示意图

select类示意图

在这里插入图片描述

cFile类示意图

在这里插入图片描述

ListStu类示意图

在这里插入图片描述

ClassStu示意图

在这里插入图片描述

项目源代码

select

select.h

#pragma once
#include <iostream>
#include "classstu.h"
#include <iomanip>
#include "cfile.h"
#include "ListStu.h"
using namespace std;
///*
//类用于在内存中管理用户信息
//提供增删改查  功能等
//*/
//
class Select
{
public:
	/*
		* select  //构造函数
		* 参数一:传入用户个数,用来申请堆空间
		* 功能  : 初始化类成员
		* 返回值 无
		*
	*/

	Select()
	{
		m_pFile = nullptr;
		m_pListStu = nullptr;
	}

	Select(const char* filename) :m_pFile(new cFile(filename))
	{
		//1 委托构造已经初始化了文件类

		//2  初始化  cmystu内存操作的类
		  //2.1:读取文件头四个字节,保存用户的个数
			int nCount = m_pFile->ReadFileHeader();
		//3实例化ListStu类
			m_pListStu = new ListStu(nCount);
	
		//4  把文件所有数据存放内存中
			m_pFile->ReadFileAllDate(m_pListStu);
	}

/*
	* ~select  //析构函数
	* 参数一:无
	* 功能  : 释放类成员申请的堆空间
	* 返回值 无
	*
*/
	~Select();


	/*
		* SelectAllDate
		* 参数一:无
		* 功能  : 把所有用户信息输出到标准设备中(屏幕)
		* 返回值 无
		*
	*/
	void SelectAllDate();

/*
	* FindOneDate
	* 参数一:myiterator
	* 功能  : 根据用户nuserid查找用户信息
	* 返回值 无
	*
*/
	bool FindOneDate(int nUserId);

	/*
		* DrawOneDate
		* 参数一:myiterator
		* 功能  : 输出传入用户的信息
		* 返回值 无
		*
	*/
	void DrawOneDate(ListStu::Iterator itr);


	/*
		* SelectFileOffOneDateId
		* 参数一:用户id号
		* 功能  : 根据用户userid,检测是否有当前用户,返回用户的文件偏移
		* 返回值 int类型;返回用户的文件偏移
		*
	*/
	int SelectFileOffOneDateId(int userid);


	/*
		* InsertOneDate
		* 参数一:字符串
		* 功能  : 内存中和文件中插入一个用户信息
		* 返回值 :bool
		*
	*/
	bool InsertOneDate(const char* susername,int nId = 0);


	/*
		* DeleteDate
		* 参数一:用户id -- userid
		* 功能  : 删除指定用户id在文件和内存中的数据
		* 返回值 :无
		*
	*/
	bool DeleteDate(int id);//删除数据

/*
	* UpDate
	* 参数一:const char*   修改的用户名
	* 参数一:用户id -- userid
	* 功能  : 修改用户数据
	* 返回值 :无
	*
*/
	bool UpDate(const char* susername, int nuserid);//修改用户数据

/*
	* callanyname   暂未实现
	* 参数一:
	* 功能  :
	* 返回值 :无
	*
*/
	//void callanyname();



/*
	* drawinit  初始化界面
	* 参数一:无
	* 功能  : //初始化界面
	* 返回值 :无
*/
	void DrawInit();//初始化界面


/*
	* drawhead
	* 参数一:无
	* 功能  : 把用户头部信息输出到标准设备中(屏幕)
	* 返回值 :无
*/
	void DrawHead();//封装显示头部
/*
	* IdEmptyFill
	* 参数一:用户id
	* 功能  : 计算id后面需要填充空格多少
	* 返回值 :无
*/
	int IdEmptyFill(int id);





/*
	* GetFlg
	* 参数一:无
	* 功能  : 获取类成员m_flg的值
	* 返回值 :bool
*/
	bool GetFlg();//记录是否有修改或删除数据的标志


/*
	* ReDEFile
	* 参数一:常量字符串  --文件名
	* 参数二:常量字符串  --新文件名
	* 功能  : 重写文件,把内存数据重新写入到文件中
	* 返回值 :bool 
	*
*/
	bool ReDEFile(const char* old_filename, const char* new_filename);//删除数据



/*
	* bubblesort
	* 参数一:无
	* 功能  : 冒泡排序法--大循环为次数,内循环为第n和第n+1依次往下对比
	* 返回值 :无
*/
	//void bubblesort();
	//排序--选择排序法 --取最小的索引;先比较数大小 --然后放在第i位
/*
	* selectionsort
	* 参数一:无
	* 功能  : 选择排序法--大循环为次数,取最小的索引;先比较数大小 --然后放在第i位
	* 返回值 :无
*/
	//void selectionsort();

	/*
		* insertsort
		* 参数一:无
		* 功能  : 插入排序法-- --依次往上对比;--   次数一次比一次对比多
		* 返回值 :无
	*/
	//void insertsort();
public:
	cFile* m_pFile;  //一个操作文件
	ListStu* m_pListStu;//一个操作内存

	bool m_flg = false;// 需要重写文件标志 记录是否有修改 或删除过数据  id为0的数据

};

select.cpp

#include "Select.h"


void Select::SelectAllDate()
{
	//显示头部标题
	DrawHead();
	//内存数据进行冒泡排序
	m_pListStu->insertionSort();
	//序号 nIndex
	int nIndex = 1;
	//int nCount = m_cMyStu->GetCount();
	//迭代器输出
	for (auto Val : *m_pListStu)
	{

		cout << nIndex << setw(14 - (IdEmptyFill(nIndex))) << " ";

		cout << Val.m_Id << setw(8 - (IdEmptyFill(Val.m_Id))) << " ";

		cout << Val.m_StuName->GetStr() << setw(14 - ((Val.m_StuName->GetLen()))) << "  ";

		cout << Val.m_FileOffset << endl;
		nIndex++;
	}

}

bool Select::FindOneDate(int nUserId)
{
	if (nUserId < 0)
	{
		return false;
	}
	//nUserId 转nIndex

	int nIndex = m_pListStu->UserIdToIndex(nUserId);
	if (nIndex == -1)
	{
		cout << "没有此用户" << endl;
		return false;
	}
	ListStu::Iterator Itr = m_pListStu->FindItr(nIndex);
	DrawOneDate(Itr);
	return true;
	
}

void Select::DrawOneDate(ListStu::Iterator Itr)
{
    DrawHead();
//	//打印pFindName查找到的用户信息
	cout << (*Itr).m_Id << setw(8 - IdEmptyFill((*Itr).m_Id)) << " ";
	cout << (*Itr).m_StuName->GetStr()<< setw(14 - (*Itr).m_StuName->GetLen()) << "  ";
	cout << (*Itr).m_FileOffset << endl;
}


//
int Select::SelectFileOffOneDateId(int UserId)
{
	//检查 UserId  // 检测最大是 也是要迭代
	if (UserId <= 0)
	{
		return 0;
	}
	for(auto Val:*m_pListStu)
	{
	
		if (UserId == Val.m_Id)
		{

			return Val.m_FileOffset;//返回在文件中的偏移
		}
		
	}
	return 0;
}

bool Select::InsertOneDate(const char* sUserName, int nUserId)
{
	//检测指针
	if (sUserName == nullptr)
	{
		cout << "sUserName写入失败" << endl;
		return false;
	}

	//如果为了就是插入新数据 否则是修改数据
	if(nUserId == 0)
	{ 
		nUserId = m_pListStu->GetMaxUserId();//用户id
		nUserId++;
	}
	ClassStu* cTmp = new ClassStu(nUserId, sUserName);
		//文件中插入数据
	m_pFile->WriteInsertFile(cTmp);
	if (cTmp == nullptr)
	{
		cout << "ClassStu* cTmp写入失败" << endl;
		return false;
	}

	    //内存插入数据
	m_pListStu->VailInsert(*cTmp);
	delete cTmp;
	return true;
}


bool Select::DeleteDate(int nId)
{
	//nId为用户序号  序号-1 为用户的数组索引
	int nIndex = nId - 1;
	//先要找到删除数据的文件偏移

	int FileOffset = m_pListStu->FindFOffset(nIndex);
	
	if (!FileOffset == 0)
	{
		//需要判断一下  是否找到了
		//获取到文件偏移 修改文件的数据 把用户Id改为0即可
		if (m_pFile->WriteDeleteFile(FileOffset) == 1)
		{
			//内存中删除
			m_pListStu->DeteleId(nIndex);
			m_flg = true;
			return m_flg;
		}
	}
	return false;
}

bool Select::UpDate(const char* sUserName, int nId)
{

	nId--;
	//nId  为用户的m_id
	if (sUserName == nullptr)
	{
		return false;
	}
	//1 文件就是先插入一个新数据,在删除一个原来的数据
	  // 1.1先文件中插入一个新数据,在删除原来的数据
	int nUserId = m_pListStu->FindId(nId);
	ClassStu* cStu = new ClassStu(nUserId, sUserName);
	if (!m_pFile->WriteInsertFile(cStu))
	{
		return false;
	}
	  //1.2文件中删除一个数据  -- 找到文件偏移
	int nFileOffset = m_pListStu->FindFOffset(nId);
	if (m_pFile->WriteDeleteFile(nFileOffset) != 1)
	{
		return false;
	}
	//2 内存中更新数据就是直接找到节点更新 	void UpDate(int nIndex,ClassStu& cStu);
	m_pListStu->UpDate(nId,*cStu);


	m_flg = true;//需要重写文件标志
	delete cStu;//释放资源
	return true;
}


void Select::DrawInit()
{
	cout << "========" << "欢迎来到电话薄操作" << "========" << endl;
	//封装一个.cpp文件
	cout << "一:显示所有数据。" << endl;
	cout << "二:查询联系人" << endl;
	cout << "三:增加联系人。" << endl;
	cout << "四:修改联系人。" << endl;
	cout << "五:删除联系人。" << endl;
	cout << "六:随机拨打任意联系人。" << endl;
	cout << "七:退出程序。" << endl;
	cout << "请选择操作:" << endl;

}

//void Select::CallAnyName()
//{
//}

void Select::DrawHead()
{
	cout << "用户序号" << setw(6) << " ";
	cout << "用户ID" << setw(4) << " ";
	cout << "用户名称" << setw(6) << "  ";
	cout << "文件偏移" << endl;
}
int Select::IdEmptyFill(int Id)
{
	int nCount = 0;
	while (Id > 9) {
		Id = Id / 10;  // 整数除法,相当于取整除
		nCount++;
	}
	return nCount;
}

	bool Select::GetFlg()
	{
		return m_flg;
	}

	bool Select::ReDEFile(const char* old_filename, const char* new_filename)
	{
		return m_pFile->ReDeFileName(old_filename, new_filename, m_pListStu);
	}

Select::~Select()
{
	delete m_pListStu;
	delete m_pFile;
}

cFile

cFile.h

#pragma once
#include <iostream>
#include "ListStu.h"
#include "VetorCstu.h"
using namespace std;

/*

* 
* 有想一起学习c++的,,一起努力坚持下去:加入(q) :553235560
*/

class cFile
{
public:
	enum FileType { WRITEERR = -3, READERR, PNULL , SUCCESS = 1 };
public:
  /*******************默认构造系列开始*************************/
/*
   * cFile
   * 参数一 : 无
   * 功能   :默认构造,初始化类成员 --为空
   * 返回值 :无
*/

	cFile();

/*
	* cFile(const char* FileName,const char* Mode)
	* 参数一 : const char* FileName --文件的目录地址
	* 功能   :默认构造打开文件,初始化类成员
	* 返回值 :无
*/
	cFile(const char* FileName);

/*
	* cFile(cFile& fFile)
	* 参数一 : 无
	* 功能   :默认构造,初始化类成员 --为空
	* 返回值 :无
*/
	cFile(const cFile& fFile);



/*
	* ~cFile()
	* 参数   :无
	* 功能   :释放类资源
	* 返回值 :无
*/
	~cFile();
	/*******************默认构造系列结束*************************/



	/*******************文件读系列开始*************************/

/*
	*  ReadFileHeader(int* nCount)
	* 参数一   :无
	* 功能   :获取文件首四个字节 为用户个数
	* 返回值 :成功返回个数,失败返回-1
*/

	int ReadFileHeader();
/*
	*  ReadFile(void* buffer,int FileOffset = 0)
	* 参数一   :void* buffer 读出数据放入的缓冲区
	* 功能   :从文件中读取数据放入缓冲区中
	* 返回值 :FileType
*/
	//FileType ReadFileAllDate(ClassStu* pStudent,int nCount);

	FileType ReadFileAllDate(ListStu* Cstu);
	/*******************文件读系列结束*************************/

	/*******************文件写系列开始*************************/

/*
	* WriteFile()
	* 参数一   :const void* buffer 要写入的字符串
	* 功能   :文件中写入一个用户信息
	* 返回值 :int   返回写入数据的文件偏移 Offset
*/
	bool WriteInsertFile(ClassStu* cStu);

/*
	* WriteFile()
	* 参数一 :int 文件偏移
	* 功能   :把指定位置四个字节填充为0;
	* 返回值 :int
*/
	int WriteDeleteFile(int FileOffset);

	/*******************文件写系列结束*************************/

/*
	*  UpDateHeader(bool bTmp);
	* 参数一   :bool ;默认是true 代表头部四个字节加1 flase 代表头部减1
	* 功能	   : 用户个数的加减操作
	* 返回值 :FileType
*/
	FileType UpDateHeader(bool bTmp = true);


	/*******************内部调用函数系列*************************/

/*
	*  ReDeFileName(const char* old_filename, const char* new_filename)
	* 参数一   :const char* old_filename 要修改的文件路径和名字
	* 参数二  :const char* new_filename 文件的新名
	* 参数三  :ClassStu* 指向用户数据的缓存
	* 参数四  :int  用户的数量
	* 功能	   :修改文件名,重新创建新的,成功后删除老的
	* 返回值 :int  成功返回0 错误非0值
*/

	bool ReDeFileName(const char* old_filename, const char* new_filename, ListStu* Cstu);



/*
	*  WriteFileAllDate(ClassStu* pStudent)
	* 参数一   :ClassStu*  
	* 功能	   : 把内存中的数据全部写入文件中
	* 返回值   :int类型  成功返回1 错误非0值
*/
	int WriteFileAllDate(ListStu* Cstu);
/*
	*  WriteOneDate(ClassStu* pStudent, int FileOffset = 0)
	* 参数一   :ClassStu*
	* 参数二   :int 
	* 功能	   : 写入一个数据
	* 返回值   :int类型  成功返回1 错误非0值
*/

	int WriteOneDate(ClassStu* cStu);

/*
	* CloseFile()
	* 参数   :无
	* 功能   :关闭文件
	* 返回值 :无
*/
	void CloseFile();

private:


/*
	* ~IsOpen()
	* 参数   :无
	* 功能   :检查m_pFile是否为nullptr.  文件是否打开成功
	* 返回值 :bool
*/
	bool IsOpen();

/*
	*  WriteFileDate(void* buffer,int nSize)
	* 参数一   :void* buffer  要写入文件的字符串缓冲区
	* 参数二   : int  nSize   要写入多少个字节
	* 功能	   :封装文件fwrite函数;使用起来更加方便
	* 返回值 :FileType
*/
	FileType WriteFileDate(void* buffer, int nSize);

/*
	*  ReadFileDate(void* buffer,int nSize)
	* 参数一   :void* buffer 读出数据放入的缓冲区
	* 参数二   : int  nSize 要从文件中读多少个字节
	* 功能	   :封装文件fread函数;使用起来更加方便
	* 返回值 :FileType
*/
	FileType ReadFileDate(void* buffer, int nSize);

	
private:

	FILE* m_pFile;//文件指针
	int* m_nCount;//引用技术,记录被赋值次数

};


cFile.cpp

#include "cFile.h"


cFile::cFile(const cFile& fFile)
{
	m_pFile = nullptr;
	m_nCount = NULL;
	if (fFile.m_pFile != nullptr)
	{
		m_pFile = fFile.m_pFile;
		m_nCount = fFile.m_nCount;
		(*m_nCount)++;
	}
}

cFile::cFile()
{
	m_pFile = nullptr;
	m_nCount = nullptr;
}

cFile::cFile(const char* FileName)
{
	//以读写方式打开文件
	fopen_s(&m_pFile, FileName, "r+b");//从文件头开始读,可读可写
	m_nCount = new int(0);
	if (!IsOpen())//文件打开不成功
	{
	//文件打开不成功,就创建一个新文件  从文件尾开始写
		fopen_s(&m_pFile, FileName, "w+b");
	
		//写入四个字节 ---也可以检测文件是否打开成功
		if (WriteFileDate(m_nCount, 4) != SUCCESS)
		{
			
			cout << "初始化失败" << endl;
		}
		fflush(m_pFile);

	}

}

cFile::~cFile()
{

	if (m_pFile == nullptr)
	{
		return;
	}

	if (*m_nCount != 0)
	{
		(*m_nCount)--;
	}
	else
	{
		CloseFile();//关闭文件
	
		cout << "关闭文件成功" << endl;
	}

}

bool cFile::IsOpen()
{
	if (m_pFile == nullptr)
	{
		return false;
	}
	return true;
}

int cFile::ReadFileHeader()
{

	//文件偏移移动到首
	rewind(m_pFile);
	int nCount = 0;
	//从文件读四个字节到nCount /成功返回读取了多少个字节
	if (fread((char*)&nCount, 1, 4, m_pFile) == 4)
	{
		return nCount;
	}
	return 0;
}



cFile::FileType cFile::ReadFileAllDate(ListStu* Cstu)
{
	//1:检测缓冲区地址是否为空
	if (Cstu == nullptr)
	{
		return PNULL;
	}
	//2:循环读取文件中用户信息--》缓存中
	for (auto Itr = Cstu->begin(); Itr != Cstu->end(); ++Itr)
	{
		
		//反序列化,从文件读到内存
		(*Itr).Deserialize(m_pFile);
	}
	return SUCCESS;


}



cFile::FileType cFile::ReadFileDate(void* buffer, int nSize)
{
	if (buffer == nullptr || nSize <= 0)
	{
		return READERR;
	}
	if (fread(buffer, 1, nSize, m_pFile) == nSize)
	{
		return SUCCESS;
	}
	return READERR;
}

bool cFile::WriteInsertFile(ClassStu* cStu)
{

	//1:判断传入的指针是否为空
	if(cStu == nullptr)
	{
		return false;
	}
	//2:将文件偏移指向要写入的位置
	if (WriteOneDate(cStu)!= SUCCESS)
	{
		return false;
	}

	//3 修改首部四个字节用户个数
	UpDateHeader();

	if (fflush(m_pFile) != 0)
	{
		cout << "写入文件失败" << endl;
		return false;
	}

	return true;
}

int cFile::WriteDeleteFile(int FileOffset)
{
	fseek(m_pFile, FileOffset, SEEK_SET);//移动到指定位置写入;
	int a = 0;
	if (WriteFileDate(&a, 4) != SUCCESS)
	{
		return WRITEERR;
	}
	fflush(m_pFile);
	return SUCCESS;
}

cFile::FileType cFile::WriteFileDate(void* buffer, int nSize)
{
	if (buffer == nullptr || nSize <= 0)
	{
		return WRITEERR;
	}

	if (fwrite(buffer, 1, nSize, m_pFile) == nSize)
	{
		return SUCCESS;
	}

	return WRITEERR;
}

void cFile::CloseFile()
{
	fclose(m_pFile);
	delete m_nCount;

	m_nCount = nullptr;
	m_pFile = nullptr;
}



bool cFile::ReDeFileName(const char* old_filename, const char* new_filename, ListStu* Cstu)
{
	//文件改名必须先关闭文件  上面已经关闭了
	CloseFile();

	if (rename(old_filename, new_filename) == 0) //文件改名.成功就创建新的
	{

		cFile FileStuu(old_filename);//实例化 文档已经写入了头部四个字节

		if (FileStuu.WriteFileAllDate(Cstu) == 1)//证明写入成功了 删除Old文件
		{
			remove("mystudate_old.bin");
			return true;
		}
	}
	return false;
}

int cFile::WriteFileAllDate(ListStu* Cstu)
{
		int  nNewCount = 0;

		for (ClassStu Val : *Cstu)
		{
			if (Val.m_Id != 0)//id不为0就是没有删除的数据  写入到文件中
			{
	
				if (WriteOneDate(&Val) != SUCCESS)
				{
					return WRITEERR;
				}
				nNewCount++;
			}
		}
	
		//最后写入个数
		fseek(m_pFile,0,SEEK_SET);
		if (WriteFileDate(&nNewCount, 4) != SUCCESS)
		{
			return WRITEERR;
		}
		fflush(m_pFile);

		return SUCCESS;
}

int cFile::WriteOneDate(ClassStu* cStu)
{
	if (cStu == nullptr)
	{
		return WRITEERR;
	}

	if (!cStu->Serialize(m_pFile))
	{
		return WRITEERR;
	}
	return SUCCESS;
}


cFile::FileType cFile::UpDateHeader(bool bTmp)
{
	//先读
	int nCount = ReadFileHeader();
	if (nCount == -1)
	{
		return READERR;
	}

	bTmp ? nCount++ : nCount--;

	fseek(m_pFile,0,SEEK_SET);//移动到头部

	//再写
	if (WriteFileDate(&nCount, 4) != SUCCESS)
	{
		return WRITEERR;
	}
	fflush(m_pFile);
	return SUCCESS;
}

ListStu

ListStu.h

#pragma once
#include "ClassStu.h"

class ListStu
{
public:
	struct StuNode
	{
		ClassStu cStu;//数据
		StuNode* pNext;//指向下一个数组


		StuNode()
		{
			pNext = nullptr;
		}
	};

	using pStuNode = StuNode*;
public:
     //迭代器类
	class Iterator
	{
	public:

		Iterator(pStuNode Head, pStuNode Vail)
		{
			m_Head = Head;
			m_Vail = Vail;

		}

		ClassStu& operator*()
		{
			return m_Head->cStu;
		}

		Iterator& operator++()
		{
			if (m_Head != m_Vail->pNext)
			{
				m_Head = m_Head->pNext;
			}
			return *this;
		}

		bool operator!=(Iterator Itr)
		{
			return m_Head != Itr.m_Head->pNext;//不等于的时候返回真
		}

	private:
		pStuNode m_Head;
		pStuNode m_Vail;
	};


public:

	/*******************默认构造系列开始*************************/
/*
   * ListStu
   * 参数一 : 无
   * 功能   :默认构造,初始化类成员 --为空
   * 返回值 :无
*/
	ListStu();


/*
	* ListStu
	* 参数一 : int
	* 功能   :默认构造,初始化nCount个成员链表
	* 返回值 :无
*/
	ListStu(int nCount);
/*
	* ~ListStu
	* 参数一 : 无
	* 功能   :默认析构,释放资源
	* 返回值 :无
*/
	~ListStu();

	/*******************默认构造系列结束*************************/

//----------------------------------------------------------------------------//
//----------------------------------------------------------------------------//
//----------------------------------------------------------------------------//

	/*******************增删改查系列开始*************************/
/*
	* HeadInsert
	* 参数一 : ClassStu
	* 功能   :从头部插入一个数据
	* 返回值 :ListStu&
*/

	ListStu& HeadInsert(ClassStu& cStu);

/*
	* VailInsert
	* 参数一 : ClassStu
	* 功能   :从尾部插入一个数据
	* 返回值 :ListStu&
*/

	ListStu& VailInsert(ClassStu& cStu);
/*
	* Insert
	* 参数一 : pStuNode 需要插入节点的位置   插在这个节点的pStuNode后面
	* 参数二 : ClassStu& 插入的数据
	* 功能   : 指定位置插入一个数据
	* 返回值 : ListStu&
*/

	ListStu& Insert(pStuNode PosNode,ClassStu& cStu);


/*
	* Detele
	* 参数一 : pStuNode    删除的前一个节点
	* 功能   : 从链表中删除一个节点
	* 返回值 : 无
*/
	void Detele(pStuNode PosNode);

/*
	* DeteleId
	* 参数一 : 索引
	* 功能   : 指定索引从链表中删除一个节点
	* 返回值 : 无
*/
	void DeteleId(int nIndex);

/*
	* DeteleHead
	* 参数一 : pStuNode   删除头部节点
	* 功能   : 删除头部节点
	* 返回值 : 无
*/
	void DeteleHead();

/*
	* Find
	* 参数一 : int --序号索引
	* 功能   : 通过索引查找到数据
	* 返回值 : 无
*/
	StuNode* Find(int nIndex);


/*
	* FindItr
	* 参数一 : int --序号索引
	* 功能   : 查找到数据
	* 返回值 : Iterator   
*/
	Iterator FindItr(int nIndex);

/*
	* FindFOffset
	* 参数一 : int --序号索引
	* 功能   : 根据索引查找到文件偏移
	* 返回值 : 无
*/
	int FindFOffset(int nIndex);

/*
	* FindId
	* 参数一 :  int --序号索引
	* 功能   : 根据索引查找到用户m_Id
	* 返回值 : 无
*/
	int FindId(int nIndex);

/*
	* UserIdToIndex
	* 参数一 :  int --用户的m_Id
	* 功能   : 用户m_Id --查到链表用户的索引
	* 返回值 : int  nIndex
*/
	int UserIdToIndex(int UserId);

/*
	* UpDate
	* 参数一 : int --序号索引
	* 功能   : 修改用户的数据
	* 返回值 : 无
*/
	void UpDate(int nIndex,ClassStu& cStu);
	/*******************增删改查系列结束*************************/


	/*******************迭代器开始*************************/
/*
	* begin
	* 参数一 : 无
	* 功能   : 迭代器开始
	* 返回值 : Iterator
*/

	Iterator begin()
	{
		return Iterator(m_HeaderStu, m_VailStu);
	}
/*
	* end
	* 参数一 : 无
	* 功能   : 迭代器结束
	* 返回值 : Iterator
*/
	Iterator end()
	{
		return Iterator(m_VailStu, m_VailStu);
	}
	/*******************迭代器结束*************************/

	/*******************内部使用函数系列开始*************************/
/*
	* InitDate
	* 参数一 : int --序号索引
	* 功能   : 初始化类成员
	* 返回值 : 无
*/
	void InitList();



/*
* GetMaxUserId
* 参数一 : 无
* 功能   : 查找用户最大的m_Id
* 返回值 : int
*/
	int GetMaxUserId();


/*
	* size
	* 参数一 : 无
	* 功能   : 获取元素个数
	* 返回值 : int
*/
	int Size();

/*
	* BubbleSort
	* 参数一 : 无
	* 功能   : 根据成员m_Id --冒泡排序
	* 返回值 : 无
*/
	//void BubbleSort();

/*
	* insertionSort
	* 参数一 : 无
	* 功能   : 根据成员m_Id --插入排序法
	* 返回值 : 无
*/
	void insertionSort();

	/*******************内部使用函数系列结束*************************/

private:
	pStuNode m_HeaderStu;//头节点
	pStuNode m_VailStu;//尾节点
	int m_nCount;//记录有多少个成员
};


ListStu.cpp

#include "ListStu.h"

ListStu::ListStu()
{
	InitList();
}

ListStu::ListStu(int nCount)
{
	InitList();
	for (int i = 0; i < nCount; i++)
	{
		ClassStu cStu;
		VailInsert(cStu);
	}
	
}

ListStu::~ListStu()
{
	//判断是否有成员
	if (m_nCount == 0)
	{
		return;
	}

	//释放资源
	//先赋值下一个,在删除当前,以此类推.
	pStuNode TmpbNode = m_HeaderStu;
	pStuNode TmpfNode = nullptr;
	for (int i = 0; i < m_nCount; i++)
	{
		TmpfNode = TmpbNode->pNext;
		delete TmpbNode;
		TmpbNode = TmpfNode;
	}
}

ListStu& ListStu::HeadInsert(ClassStu& cStu)
{
	//当数据为是空的时候
	if (m_nCount == 0)
	{
		m_HeaderStu->cStu = cStu;
		//赋值尾节点  //当头部插入时, 尾节点就是第一个插入的头节点
		m_VailStu = m_HeaderStu;
		m_nCount++;
		return *this;
	}
	//当数据不为是空的时候

	//1 实例化一个新节  等于头的数据
	pStuNode pNewNode = new StuNode;
	pNewNode->cStu = cStu;
	pNewNode->pNext = m_HeaderStu;
	//2:在把头节点赋值为pNewNode
	m_HeaderStu = pNewNode;
	m_nCount++;

	return *this;

}

ListStu& ListStu::VailInsert(ClassStu& cStu)
{
	return Insert(m_VailStu, cStu);
}

ListStu& ListStu::Insert(pStuNode PosNode, ClassStu& cStu)
{
	//插入第一个数据是头部数据
	if (m_nCount == 0)
	{
		return HeadInsert(cStu);
	}
	//新增节点
	pStuNode pNewNode = new StuNode;
	pNewNode->cStu = cStu;
	//节点放在PosNode后面,先要把PosNode-》pNext的值给新节点
	pNewNode->pNext = PosNode->pNext;
	//然后把新节点放在PosNode->pNext
	PosNode->pNext = pNewNode;

	//判断尾节点的赋值
	if (PosNode == m_VailStu)
	{
		//尾节点赋值
		m_VailStu = pNewNode;
	}

	m_nCount++;
	return *this;
}

void ListStu::Detele(pStuNode PosNode)
{

	if (PosNode->pNext == m_VailStu)
	{
		m_VailStu = PosNode;
	}
	//这个是要被删除的节点
	pStuNode DeleteNode = PosNode->pNext;
	//删除前----先断链它
	PosNode->pNext = DeleteNode->pNext;
	//在把资源释放掉
	delete DeleteNode;
	m_nCount--;
}

void ListStu::DeteleId(int nIndex)
{
	if (nIndex == 0)//那么就是删除头部
	{
		DeteleHead();
		return;
	}
	--nIndex;
	pStuNode bDeleteNode = Find(nIndex);

	Detele(bDeleteNode);
}

void ListStu::DeteleHead()
{
	//这个是需要被删除的节点
	pStuNode DeleteNode = m_HeaderStu;
	//重新赋值新的头部
	m_HeaderStu = m_HeaderStu->pNext;
	//释放资源
	delete DeleteNode;
	m_nCount--;
}



ListStu::StuNode* ListStu::Find(int nIndex)
{

	//判断 成员个数不为0  nIndex是否有效的值
	if (m_nCount < 1 ||nIndex < 0 || nIndex > m_nCount)
	{
		return nullptr;
	}

	//遍历查找数据    
	pStuNode FindNode = m_HeaderStu;

	for (int i = 0; i < nIndex; i++)
	{
		FindNode = FindNode->pNext;

	}
	return FindNode;
}

ListStu::Iterator ListStu::FindItr(int nIndex)
{
	return Iterator(Find(nIndex),m_VailStu);
}

int ListStu::FindFOffset(int nIndex)
{
	pStuNode pFindNode = Find(nIndex);
	if (pFindNode == nullptr)
	{
		return 0;
	}
	return pFindNode->cStu.m_FileOffset;
}

int ListStu::FindId(int nIndex)
{
	pStuNode pFindNode = Find(nIndex);
	if (pFindNode == nullptr)
	{
		return 0;
	}
	return pFindNode->cStu.m_Id;
}

int ListStu::UserIdToIndex(int UserId)
{
	int nIndex = 0;
	for (auto Val : *this)
	{
		if (UserId == Val.m_Id)
		{
			return nIndex;
		}
		nIndex++;
	}
	return -1;
}

void ListStu::UpDate(int nIndex, ClassStu& cStu)
{

	//先找到要修改的数据
	pStuNode pUpDate = Find(nIndex);
	//替换数据   -- cStu里面会自动释放资源
	pUpDate->cStu = cStu;
}

void ListStu::InitList()
{
	m_HeaderStu = new StuNode;
	m_VailStu = nullptr;
	m_nCount = 0;
}

int ListStu::GetMaxUserId()
{
	int nMaxId = 1;
	for (auto Val:*this)
	{
		if (nMaxId < Val.m_Id)
		{
			nMaxId = Val.m_Id;
		}
	}
	return nMaxId;
}

int ListStu::Size()
{
	return m_nCount;
}


用排序法更适合
//void ListStu::BubbleSort()
//{
//	int nCount = m_nCount - 1;
//	pStuNode TmpNode = m_HeaderStu;
//	pStuNode TmpnNode = m_HeaderStu;
//
//	pStuNode ReNode = TmpNode;
//
//	for (int i = 0; i < nCount; i++)
//	{
//
//		for (int j = 0; j < nCount - i; j++)
//		{
//			if (TmpNode->cStu.m_Id > TmpnNode->pNext->cStu.m_Id)
//			{
//				TmpNode = TmpnNode->pNext;
//				
//
//			}
//			TmpnNode = TmpnNode->pNext;
//		}
//		//断链不好处理  		//处理头部赋值
//		if (TmpNode == m_HeaderStu && i == 0)
//		{
//			m_HeaderStu = TmpNode;
//			ReNode = m_HeaderStu;
//			TmpNode = m_HeaderStu->pNext;
//
//			continue;
//		}
//		//重新把链表串起来
//		ReNode->pNext = TmpNode;
//		ReNode = ReNode->pNext;
//
//	
//
//		//尾部赋值----需要完善
//		//if(i == nCount)
//		//{
//		//	m_VailStu = TmpNode;
//		//	break;
//		//}
//
//	}
//}
	// 插入排序算法  
	void ListStu::insertionSort()
	{
		pStuNode sorted = NULL;  // 已排序的链表  
		pStuNode current = m_HeaderStu;  // 当前需要排序的链表  

		while (current != NULL) {
			pStuNode next = current->pNext;  // 保存下一个节点  

			// 插入当前节点到已排序的链表中  
			pStuNode prev = NULL;
			pStuNode last = sorted;

			while (last != NULL && last->cStu.m_Id < current->cStu.m_Id) {
				prev = last;
				last = last->pNext;
			}

			// 调整指针  
			current->pNext = last;
			if (prev == NULL) {  //一个是插前
				sorted = current;
			}
			else {
				prev->pNext = current;//一个是插后
			}
			//赋值尾部指针
			if (last == nullptr)
			{
				m_VailStu = current;
			}

			current = next;
		}

		m_HeaderStu = sorted;  // 更新原始链表  
	}




ClassStu

ClassStu.h

#pragma once
#include "ClassStr.h"
class ClassStu
{
public:
	/*******************构造函数系列开始***********************/
/*
	* ClassStu
	* 参数一 : int --学生Id
	* 参数二 : ClassStr字符串 --学生姓名
	* 参数三 : int --文件中的储存偏移
	* 功能   :默认构造,初始化类成员 --为空
	* 返回值 :无
*/
	ClassStu();

	/*
		* ClassStu(ClassStu& cStu)
		* 参数一 : ClassStu&
		* 功能   :默认构造,浅拷贝
		* 返回值 :无
	*/
	ClassStu(ClassStu& cStu);


/*
	* ClassStu
	* 参数一 : int --学生Id
	* 参数二 : ClassStr字符串 --学生姓名
	* 参数三 : int --文件中的储存偏移
	* 功能   :默认构造,初始化类成员 --为空
	* 返回值 :无
*/
	ClassStu(int Id, const char* Name, int FileOffset = 0);



/*
	* ClassStu(int Id, const char* Name, int FileOffset = 0)
	* 参数一 : int --学生Id
	* 参数二 : MyStr*字符串 --学生姓名
	* 参数三 : int --文件中的储存偏移
	* 功能   :默认构造,初始化类成员 --为空
	* 返回值 :无
*/
	ClassStu(int Id, MyStr* cStr, int FileOffset = 0);
/*
	* ClassStu
	* 无
	* 功能   :析构函数 --释放空间资源
	* 返回值 :无
*/
	~ClassStu();

	/*******************构造函数系列结束***********************/

	/*******************运算符重载***********************/


/*
	* operator=
	* 参数一 :ClassStu*
	* 功能   :=号运算符重载,浅拷贝
	* 返回值 :无
*/ 


	void operator=(ClassStu* cStu);

/*
	* operator=
	* 参数一 :ClassStu&
	* 功能   :=号运算符重载,浅拷贝
	* 返回值 :无
*/

	//void operator=(ClassStu cStu);

/*
	* operator=
	* 参数一 :ClassStu&
	* 功能   :=号运算符重载,浅拷贝
	* 返回值 :ClassStu&   可以连续=  a=b=c  注:当函数返回时就可以等了   
*/

	ClassStu& operator=(ClassStu& cStu);



/*
	* operator*
	* 参数一 :ClassStu
	* 功能   :*运算符重载,返回用户姓名缓存
	* 返回值 :char*
*/

	char* operator*();




/*
	* operator==
	* 参数一 :ClassStu
	* 功能   :判断是否为空类
	* 返回值 :char*
*/

	bool operator== (void* pVoid);

	/*******************获取类成员***********************/
/*
	* IsEmpty()
	* 参数一 :无
	* 功能   :判断是否为空  m_StuName
	* 返回值 :bool  字符串不为空返回真 为空返回假
*/
	bool IsEmpty();

/*
	* InitClass()
	* 参数一 :无
	* 功能   :封装初始化成员函数
	* 返回值 :无
*/
	void InitClass();

/*
	* IsClear()
	* 参数一 :无
	* 功能   :清除自身
	* 返回值 :无
*/
	void IsClear();
	/*******************获取类成员结束***********************/

	/*******************序列化***********************/

	bool Serialize(FILE* pFile);//序列化--从内存写入文件

	bool Deserialize(FILE* pFile);//反序列化--从文件读到内存

	/*******************序列化***********************/
//类成员信息公开
public:
	int m_Id; //ID
	MyStr* m_StuName;//用户名称
	int m_FileOffset;//存在文件的偏移

	int* m_nIndex;
};


ClassStu.cpp

#include "ClassStu.h"

ClassStu::ClassStu()
{
	InitClass();

}


ClassStu::ClassStu(ClassStu& cStu)
{
	if (cStu == nullptr || cStu.m_StuName == m_StuName)
	{
		InitClass();
		return;
	}

	if (cStu.m_nIndex == nullptr)
	{
		//引用技术
		cStu.m_nIndex = new int(0);
	}

	m_Id = cStu.m_Id;
	m_FileOffset = cStu.m_FileOffset;
	m_StuName = cStu.m_StuName;
	m_nIndex = cStu.m_nIndex;
	(*m_nIndex)++;

}

ClassStu::ClassStu(int Id, const char* Name, int FileOffset)
{
	if (Name == nullptr)
	{
		InitClass();
		return;
	}
	m_StuName = new MyStr(Name);
	m_nIndex = new int(0);
	m_Id = Id;
	m_FileOffset = FileOffset;

}

ClassStu::ClassStu(int Id, MyStr* cStr, int FileOffset)
{
	if (cStr == nullptr)
	{
		InitClass();
		return;
	}
	m_StuName = cStr;
	m_nIndex = new int(0);
	m_Id = Id;
	m_FileOffset = FileOffset;


}

ClassStu::~ClassStu()
{
	IsClear();
}

void ClassStu::operator=(ClassStu* cStu)
{

	if (cStu == nullptr || cStu->m_StuName == m_StuName)
	{
		InitClass();
		return;
	}

	if (cStu->m_nIndex == nullptr)
	{
		//引用技术
		cStu->m_nIndex = new int(0);
	}

	//先清除自身
	IsClear();
	m_Id = cStu->m_Id;
	m_FileOffset = cStu->m_FileOffset;
	m_StuName = cStu->m_StuName;

	m_nIndex = cStu->m_nIndex;
	(*m_nIndex)++;
}

ClassStu& ClassStu::operator=(ClassStu& cStu)
{

	if (cStu == nullptr || cStu.m_StuName == m_StuName)
	{
		return *this;
	}

	if (cStu.m_nIndex == nullptr)
	{
		//引用技术
		cStu.m_nIndex = new int(0);
	}
	//先清除自身
	IsClear();
	m_Id = cStu.m_Id;
	m_FileOffset = cStu.m_FileOffset;
	m_StuName = cStu.m_StuName;
	m_nIndex = cStu.m_nIndex;
	(*m_nIndex)++;
	return *this;
}





char* ClassStu::operator*()
{
	return m_StuName->GetStr();
}

bool ClassStu::operator==(void* pVoid)
{
	if (this == nullptr)
	{
		return true;
	}
	return false;
}

bool ClassStu::IsEmpty()
{
	return m_StuName->GetStr() != nullptr;
}

void ClassStu::InitClass()
{

	m_StuName = nullptr;
	m_nIndex = nullptr;
	m_Id = 0;
	m_FileOffset = 0;

}

void ClassStu::IsClear()
{
	if (m_StuName == nullptr)
	{
		return;
	}
	if (*m_nIndex != 0)
	{
		(*m_nIndex)--;
		return;
	}

	cout << "m_StuName" << m_Id << endl;
	delete m_nIndex;
	delete m_StuName;
}

bool ClassStu::Serialize(FILE* pFile)
{
	//2:将文件偏移指向要写入的位置

	fseek(pFile, 0, SEEK_END);//移动到尾部开始写入

	//3.0 获取文件偏移,后面可以写入
	int FileOffset = ftell(pFile);
	m_FileOffset = FileOffset;

	if (FileOffset == -1L)
	{
		return false;
	}
	//3.1 先写入学生Id

	if (fwrite(&m_Id, 1, 4, pFile) != 4)
	{
		return false;
	}

	//3.2 再写入用户名称的字符串长度
	char nLen = m_StuName->GetLen();
	if (fwrite(&nLen, 1, 1, pFile) != 1)
	{
		return false;
	}
	//3.3 写入用户的姓名
	if (fwrite(m_StuName->GetStr(), 1, nLen, pFile) != nLen)
	{
		return false;
	}
	//3.4 写入文件偏移
	if (fwrite(&FileOffset, 1, 4, pFile) != 4)
	{
		return false;
	}


	return true;
}

bool ClassStu::Deserialize(FILE* pFile)
{

	//2.1 先读用户的ID
	if (fread(&m_Id, 1, 4, pFile) != 4)
	{
		return false;
	}
	//2.2 在读字符串的字节数
	char nLen = 0;
	if (fread(&nLen,1, 1, pFile) != 1)
	{
		return false;
	}
	//2.3 在读字符串
	m_StuName = new MyStr(nLen);
	if (fread(m_StuName->GetStr(), 1, nLen, pFile) != nLen)
	{
		return false;
	}

	//2.4 在读文件偏移
	if (fread(&m_FileOffset, 1, 4, pFile) != 4)
	{
		return false;
	}

	return true;

}

main 源码

#include "Select.h"
#include <conio.h>


int main()
{
	//初始化;已经把文件数据读入内存中
	Select MySele2("mystudate.bin");
	int selectId = 0;	//保存操作的选择
	while (selectId != 7)
	{
		system("cls");
		//初始化界面
		MySele2.DrawInit();
		scanf_s("%d", &selectId);//获取用户的输入
		if (selectId < 0 || selectId > 7)
		{
			cout << "输入错误,请重新输入" << endl;
			continue;
		}

		switch (selectId)
		{
			case 1:
			{
				MySele2.SelectAllDate();//显示所有数据
			
				break;

			}
			case 2://查询单个联系人
			{
				
				int nUserId = 0;
				cout << "请输入用户Id:" << endl;
				scanf_s("%d",&nUserId);
				MySele2.FindOneDate(nUserId);
				break;
			}
			case 3://增加联系人
			{
				char sUserName[32] = { 0 };//保存用户的输入查找用户名
				memset(sUserName, 0, 32);
				cout << "请输入姓名:" << endl;
				//获取到用户输入的姓名
				scanf_s("%s", sUserName, 32);
				MySele2.InsertOneDate(sUserName);
				break;
			}
			case 4://修改联系人
			{
				char sUserName[32] = { 0 };//保存用户的输入查找用户名
				memset(sUserName, 0, 32);
				//先修改文件 :先把要修改的删除操作,在新增一项即可 ,序号
				int nId = 0;
				cout << "请输入要求改的用户序号" << endl;
				scanf_s("%d", &nId);
				//获取成员个数、 检测是否超出边界
				int nSize = MySele2.m_pListStu->Size();
		
				if (nId < 1 || nId > nSize)
				{
					cout << "删除失败" << endl;
					break;
				}

				cout << "请输入要修改的名字" << endl;
				scanf_s("%s", sUserName, 32);
				
				//修改数据
				MySele2.UpDate(sUserName, nId);
			

				break;
			}
			case 5://删除联系人
			{
			
				//填写用户ID
				cout << "请输入要删除的用户序号" << endl;
				int nIndex = 0;
				scanf_s("%d", &nIndex);

				int nSize = MySele2.m_pListStu->Size();
				if (nIndex < 1 || nIndex > nSize)
				{
					cout << "删除失败" << endl;
					break;
				}

				if (MySele2.DeleteDate(nIndex) == false)
				{
					cout << "删除失败" << endl;
				}

			}
		
		}

		system("pause");


	}
	//退出后,如果有删除 修改文件。则要重写文件
	if (MySele2.GetFlg())
	{
		//重新将内存数据写入文件
		MySele2.ReDEFile("mystudate.bin", "mystudate_old.bin");
	}
	return 0;

}


  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值