前言:
由于数据结构掌握的不太扎实,最近重新学习了一遍数据结构,因为我发现大部分数据结构的教学内容用的都是伪代码或者纯C语言,而C++的一大优点泛型编程却没怎么被提起,所以打算从头开始用泛型编程简单的去实现所有的数据结构类型。
正文:
以下是一个简单的C++泛型编程实现的链表,仅供参考。
myList.hpp
C++泛型编程的头文件是.hpp格式,具体要想了解的可以百度,这里不做多余赘述
#include<iostream>
//C++ 模板链表的实现,带头结点
using namespace std;
template<class T>
class LNode {
public:
T data;
LNode* next;
};
template<class T>
class Link {
private:
LNode<T>* frist;
int sz;
public:
Link();
Link(int sz);
~Link();
//展示数据
void show();
T& operator[](int pos);
//插入与删除
void insert(int pos,const T &elem);
void erase(int pos);
//清空
void clear();
//判断是否为空
bool isEmpty();
//获取数据元素个数
int size();
//查找下标(第一次出现)
int find(const T &elem);
//查找下标(指定起始位置)
int find(int beg,const T &elem);
//查找出现次数
int count(const T &elem);
};
template<class T>
inline Link<T>::Link()
{
this->frist = new LNode<T>;
this->sz = 0;
this->frist->next = NULL;
}
template<class T>
inline Link<T>::Link(int sz)
{
//尾插法数据由用户输入
this->frist = new LNode<T>;
this->frist->next = NULL;
this->sz = sz;
LNode<T>* pend = this->frist;//尾结点
int i = 0;
while (i < sz)
{
LNode<T>* pnew = new LNode<T>;
pnew->next = NULL;
cout << "请输入: ";
cin >> pnew->data;
cout << endl;
pend->next = pnew;
pend = pnew;//尾结点等于新节点
i++;
}
}
template<class T>
inline Link<T>::~Link()
{
if (this->sz == 0)
{
delete this->frist;
return ;
}
LNode<T>* p = this->frist->next;//找到头结点指向的下一个结点
while (p != NULL)
{
LNode<T>* del = p;
p = p->next;
//测试是否数据被正常析构
//cout << "数据: " << del->data << "已释放" << endl;
delete del;
}
delete this->frist;//最后释放头结点
}
template<class T>
inline void Link<T>::show()
{
if (this->sz == 0)
{
cout << "[ ]" << endl;
return;
}
cout << "[ ";
LNode<T>* p = this->frist->next;
while (p != NULL)
{
cout << p->data << " ";
p = p->next;
}
cout << "]" << endl;
}
template<class T>
T& Link<T>::operator[](int pos)
{
if (pos > this->sz - 1 || pos < 0)
{
cout << "坐标有误" << endl;
T err = 0;
return err;
}
LNode<T>* p = this->frist;
for (int i = 0; i <= pos; i++)
{
p = p->next;
}
return p->data;
}
template<class T>
inline void Link<T>::insert(int pos, const T& elem)
{
if (pos > this->sz || pos < 0)
{
cout << "error: the pos is error" << endl;
return ;
}
LNode<T>* p = this->frist;
for (int i=0;i<=pos-1;i++)
{
p = p->next;
}
LNode<T>* pnew = new LNode<T>;
pnew->data = elem;
pnew->next = p->next;
p->next = pnew;
this->sz++;
return ;
}
template<class T>
inline void Link<T>::erase(int pos)
{
if (pos < 0 || pos >= this->sz)
{
cout << "the pos is error" << endl;
return;
}
LNode<T>* p = this->frist;
for (int i=0;i<pos;i++)
{
p = p->next;
}
//当心内存泄漏!!!
LNode<T>* del = p->next;
p->next = p->next->next;
delete del;
this->sz--;
}
template<class T>
inline void Link<T>::clear()
{
if (this->frist->next == NULL)
{
return;
}
LNode<T>* p = this->frist->next;
while (p != NULL)
{
LNode<T> *del = p;
p = p->next;
delete del;
}
this->frist->next = NULL;
this->sz = 0;
}
template<class T>
inline bool Link<T>::isEmpty()
{
if (this->frist->next == NULL && this->sz == 0)
return true;
return false;
}
template<class T>
inline int Link<T>::size()
{
return this->sz;
}
template<class T>
inline int Link<T>::find(const T& elem)
{
LNode<T>* p = this->frist->next;
int i = 0;
while (p != NULL && p->data!=elem)
{
p = p->next;
i++;
}
if (p == NULL)
{
return -1;
}
return i;
}
template<class T>
inline int Link<T>::find(int beg, const T& elem)
{
if (beg<0 || beg>this->sz - 1)
{
cout << "起始坐标有误" << endl;
return -1;
}
LNode<T>* p = this->frist->next;
int i = 0;
while ( i<=beg )
{
p = p->next;
i++;
}
//从前驱开始查找
while (p != NULL && p->data != elem)
{
p = p->next;
i++;
}
if (p != NULL) return i;
else return -1;
}
template<class T>
inline int Link<T>::count(const T& elem)
{
int count=0;
LNode<T>* p = this->frist->next;
while (p!=NULL)
{
if (p->data == elem)
{
count++;
}
p = p->next;
}
return count;
}
test.cpp
测试代码:
#pragma once
#include<iostream>
#include"myList.hpp"
using namespace std;
void test01()
{
Link<int> lnk(5);
lnk.show();
int a = lnk.find(1);
while (a != -1)
{
cout << "找到: " <<"下标:"<<a<<" "<< lnk[a] << endl;
a = lnk.find(a,1);
}
int b = lnk.count(1);
cout << "共出现:" << b << "次" << endl;
}
int main()
{
test01();
return 0;
}
注意:
测试代码只提供了一部分测试数据,想要测试自定义类型需要额外重载几个运算符,这只是一个向C++模板编程靠拢的demo版本。