今天我们用C++来实现顺序表和链表,
因为C和C++是两种在思维方式上不同,语法上很相同的语言,所以要求我们能够在两种思维中转换。
由于在上篇中我们都用int类型来做Elementype,本篇中我们利用泛型类来编写,使它们具有同用性
1.C++泛型顺序表
我们将顺序表封装成一个类,将数据指针,和长度,容量做为3个顺序表的成员,
把具体的操作函数写成一个个方法(有必要时重载以实现不同的功能)
下面给出顺序表的定义
template <class T>
class SQList{
private:
T*elem; //指向数据空间的指针
int length; //长度
int listsize; //容量
public:
/* 具体的各种操作方法 */
};
由于对象的生成会自动的调用构造函数,
生命周期结束时会自动调用析构函数,
所以我们把顺序表的初始化放在构造函数中,把表的释放放在析构函数中
代码如下
template <class T> //声明模板T
SQList<T>::SQList(int listsize)
{
elem = new T[listsize]; //在内存中开辟传入的listsize个空间
length = 0; //初始化表长为0
this->listsize = listsize;
}
template <class T>
SQList<T>::~SQList() //析构函数
{
delete[] elem; //释放开辟的内存空间
elem = NULL;
}
现在就完成了构造和析构的步骤
现在我们就需要实现插入和删除操作
template <class T>
bool SQList<T>::insertlist(int pos,T e) //插入函数
{
if(pos>length||pos<1)return false; //避免传入错误的插入位置
T*weiba = &elem[length-1]; //得到尾元素的地址
T*temp = &elem[pos-2]; //得到要插入元素得前一个元素地址
for(temp++;weiba>=temp;weiba--)*(weiba+1) = *weiba; //原来位置以后得元素向后一位
T*need = &elem[pos-1]; //得到要插入位置的地址
*need = e; //保存数据e
length++; //长度加一
return true;
}
template <class T>
bool SQList<T>::deletelist(int pos)
{
if(pos>length||pos<1)return false; //避免传入错误的删除位置
T*weiba = &elem[length-1]; //得到表尾得地址
T*temp = &elem[pos]; //得到要删除得后一个位置
for(temp;weiba>=temp;temp++)*(temp-1) = *temp; //从后向前覆盖
length--; //长度减一
return true;
}
我们看过程中观察效果,我们写一个显示数据的方法
template <class T>
void SQList<T>::showdata()
{
for(int i = 0;i<length;i++)
{
cout<<"| "<<elem[i]<<"\n------------\n"<<endl;
}
}
接下来是合并表方法
void SQList<T>::SQListcombine(SQList*s1,SQList*s2,SQList*newbase)
{
T*p1 = s1->elem; //得到表头
T*p2 = s2->elem; //得到表头
newbase->elem = new T[s1->listsize+s2->listsize]; //新表开辟内存
T*p1_last = s1->elem+s1->length-1; //得到表尾
T*p2_last = s2->elem+s2->length-1; //得到表尾
T*p3 = newbase->elem; //得到新表的表头
while(p1<=p1_last)*p3++ = *p1++; //写入
while(p2<=p2_last)*p3++ = *p2++;
newbase->length = s1->length+s2->length;
newbase->listsize = s1->listsize+s2->listsize;
}
自此一个比较完整的顺序表就出来了。
下面给出我写的一个已经封装好的顺序表类的源码(使用泛型)
#ifndef _GENSQLIST_H_
#define _GENSQLIST_H_
#include <iostream>
#include <string>
using namespace std;
template <class T>
class SQList{
private:
T*elem;
int length;
int listsize;
public:
SQList(){
};
SQList(int listsize);
~SQList();
void writedata(int tohow);
void showdata();
bool insertlist(int pos,T e);
bool deletelist(int pos);
void SQListcombine(SQList*s1,SQList*s2,SQList*newbase);
};
template <class T>
SQList<T>::SQList(int listsize)
{
elem = new T[listsize];
length = 0;
this->listsize = listsize;
}
template <class T>
SQList<T>::~SQList()
{
delete[] elem;
elem = NULL;
}
template <class T>
void SQList<T>::writedata(int tohow)
{
T*temp = elem;
for(int i = 0;i<tohow;i++,temp++)
{
T element;
cin>>element;
*temp = element;
length++;
}
}
template <class T>
void SQList<T>::showdata()
{
for(int i = 0;i<length;i++)
{
cout<<" "<<elem[i]<<"\n---------\n"<<endl;
}
}
template <class T>
bool SQList<T>::insertlist(int pos,T e)
{
if(pos>length||pos<1)return false;
T*weiba = &elem[length-1];
T*temp = &elem[pos-2];
for(temp++;weiba>=temp;weiba--)*(weiba+1) = *weiba;
T*need = &elem[pos-1];
*need = e;
length++;
return true;
}
template <class T>
bool SQList<T>::deletelist(int pos)
{
if(pos>length||pos<1)return false;
T*weiba = &elem[length-1];
T*temp = &elem[pos];
for(temp;weiba>=temp;temp++)*(temp-1) = *temp;
length--;
}
template <class T>
void SQList<T>::SQListcombine(SQList*s1,SQList*s2,SQList*newbase)
{
T*p1 = s1->elem;
T*p2 = s2->elem;
newbase->elem = new T[s1->listsize+s2->listsize];
T*p1_last = s1->elem+s1->length-1;
T*p2_last = s2->elem+s2->length-1;
T*p3 = newbase->elem;
while(p1<=p1_last)*p3++ = *p1++;
while(p2<=p2_last)*p3++ = *p2++;
newbase->length = s1->length+s2->length;
newbase->listsize = s1->listsize+s2->listsize;
}
#endif
下面是我以前写的一个typedef以int为类型的顺序表
#pragma once
#ifndef _MYSQLIST_H_
#define _MYSQLIST_H_
#include <iostream>
#include <string>
typedef int Elemtype;
using namespace std;
class SQList {
private:
Elemtype *elem;
int length;
int listsize;
public:
SQList(int listsize);
SQList(){} //这个构造函数的重载使我们可以不对对象进行实体化
~SQList(); //析构函数,释放申请的内存空间
void appendsize(int howmuch); //追加申请HOWMUCH内存空间
void writedata(int times); //从表得第一位输入数据times次
bool writedata(int beg, int end); //从表的第BEG到END位输入数据END-BEG次
void showlist(int towhere); //输入顺序表的值
void showlist();
bool insertlist(int pos, Elemtype e); //在POS处插入元素E
bool deletlist(int pos,Elemtype*e);//传入一个Elemtype类型得到要删除得数据,用来回滚
void Listcombine(SQList*q, SQList*p,SQList*Lc); //传入前面两个表的地址,合并到第三个表
bool sortlist(bool flag); //排序函数,T为 大到小的选择法排序
void toRerseve(); //元素倒置函数
};
SQList::SQList(int listsize) { //顺序表构造函数,开辟空间,初始化顺序表
elem = new Elemtype[listsize];
length = 0;
this->listsize = listsize;
}
void SQList::writedata(int times) {
Elemtype *p = elem;
for (int i = 0; i < times; i++,p++) {
cin >> *p;
}
length += times;
}
void SQList::showlist(int towhere) {
Elemtype *p = elem;
for (int i = 0; i < towhere; i++, p++) {
cout << " " << *p << "\n---------\n" << endl;
}
}
void SQList::showlist(){
Elemtype*temp = elem;
for(int i = 0;i<length;i++,temp++)
{
cout<<" "<<*temp<<"\n-----------\n"<<endl;
}
}
bool SQList::insertlist(int pos, Elemtype e) { //顺序表插入方法
if (pos<0 || pos>length - 1)return false; //插入错误情况
Elemtype *point = elem+length-1; //表尾
Elemtype *q = elem + pos-1; //得到插入位置得地址
for (int i = length - 1; i > pos-1; i--,point--)
{
*(point+1) = (*point);
}
*q = e;
length += 1;
return true;
}
bool SQList::deletlist(int pos, Elemtype*e) { //删除方法
if (pos<0 || pos>length - 1)return false;
Elemtype *p1 = elem + pos-1;
Elemtype *p2 = elem + length-1;
e = p1; //得到要删除得元素地址,给我们传入得地址
for (int i = pos; i < length - 1; i++,p1++) { //后一个去覆盖前一个
*(p1 - 1) = *(p1);
}
*p2 = NULL;
length--;
return true;
}
SQList::~SQList() { //析构函数
delete[] elem;
elem = NULL;
}
void SQList::Listcombine(SQList*q, SQList*p,SQList*Lc) { //合并表函数
Elemtype *pa = q->elem;
Elemtype *pb = p->elem;
Elemtype *pa_last = q->elem + q->length - 1;
Elemtype *pb_last = p->elem + p->length - 1;
Elemtype *pc = Lc->elem;
while (pa <= pa_last)*pc++ = *pa++;
while (pb <= pb_last)*pc++ = *pb++;
}
void SQList::appendsize(int howmuch) { //追加空间函数
Elemtype *newsize = new Elemtype[listsize + howmuch];
Elemtype *tmp2 = newsize;
Elemtype *fade = elem;
int i = 0;
while (i < length) {
*tmp2++ = *elem++;
i++;
}
length += howmuch;
listsize += howmuch;
elem = newsize;
delete[] fade;
}
bool SQList::writedata(int beg, int end) { //重载输入数据函数
Elemtype *findpos = elem + beg-1;
Elemtype *theend = elem + beg + end-2;
for (int i = 0; i < end-beg+1 ; i++,findpos++)
{
cin >> *findpos;
}
return true;
}
bool SQList::sortlist(bool flag) //flag控制排序方式
{
if(flag){
Elemtype swap1=NULL; //交换用变量
Elemtype*temp1 = elem; //得到数组得地址
for(int i = 0;i<length-1;i++)
{
for(int j = i+1;j<length;j++) //选择法大到小排序的操作
{
if(*(temp1+i)<*(temp1+j))
{
swap1 = *(temp1+i); //交换
*(temp1+i) = *(temp1+j);
*(temp1+j) = swap1;
}
}
}
return false;
}
else{
Elemtype swap2; //交换用变量
Elemtype*temp1 = elem; //得到顺序表地址
for(int i = 0;i<length-1;i++) //冒泡小到大
{
for(int j =0;j<length-1-i;j++)
{
if(temp1[j]>temp1[j+1])
{
swap2 = *(temp1+j);
*(temp1+j) = *(temp1+j+1);
*(temp1+j+1) = swap2;
}
}
}
return 0;
}
}
void SQList::toRerseve()
{
Elemtype*temp = elem;
Elemtype tohuan;
for(int i = 0;i<(length/2);i++)
{
tohuan = *(temp+i);
*(temp+i) = *(temp+length-1-i);
*(temp+length-1-i) = tohuan;
}
}
#endif // !_MYSQLIST_H_
2.C++泛型链表
同样,按照我在上篇中的导图只要把Linkedlist结构体封装成一个类。
结构就像如下
template <class T>
struct Node{
T data;
Node<T> *next;
};
template <class T>
class linklist{
private:
Node<T> * Head;
int length1;
public:
/*方法列表*/
同样是用构造函数和析构函数来实现初始化和内存释放
不过析构函数可要复杂一些
template <class T>
linklist<T>::linklist(){ //构造函数
Head = new Node<T>; //开辟头节点
Head->next = NULL; //指向空
length1 = 0; //初始化长度为0
}
template <class T>
linklist<T>::~linklist() //析构函数
{
Node<T>*temp = NULL; //定义一个临时的指针
Node<T>*p = Head->next; //p和temp形成循环释放头节点之后的节点
while(p!=NULL){
temp = p->next;
delete p;
p = temp;
}
delete Head;
Head = NULL;
cout<<"................."<<endl;
length1 = 0;
}
有了初始化之后
就要有头插和尾插的方法
template <class T>
void linklist<T>::adddata(T Data) //尾部插入
{
Node<T> *p = new Node<T>; //开辟新的节点
p->data = Data; //保存数据
p->next = NULL; //后指针指向空
Node<T>*p1 = Head; //得到头节点的地址
while(p1->next!=NULL){
p1 = p1->next; //循环指向尾节点
}
p1->next =p ; //链接
length1++;
}
template <class T>
void linklist<T>::fadddata(T e) //头插方法
{
Node<T>*temp = new Node<T>; //开辟新节点
temp->data = e; //保存数据
Node<T>*p1 = Head; //建立链接
temp->next = p1->next;
p1->next = temp;
length++;
}
接下来是位插入函数
template <class T>
bool linklist<T>::insertdat(T Data,int pos)
{
if(pos>length1-1||pos<1)return false; //避免错误的输入
Node<T>*temp = Head; //得到头节点地址
int k = 0;
while(k<pos-1){ //找到要插入节点的前一个节点
temp = temp->next;
k++;
}
Node<T>*tempneichun = new Node<T>; //开辟节点
tempneichun->data = Data; //保存数据
tempneichun->next = temp->next; //链接
temp->next = tempneichun;
length1++;
return true;
}
在下面是定位删除方法
template <class T>
T linklist<T>::deletedat(int pos){
if(pos>length1-1||pos<1)return 0; //避免错误的输入
Node<T>*temp = Head;
int k = 0;
while(k<pos-1)
{
temp = temp->next; //找到要插入节点的前一个节点
k++;
}
Node<T>*p = temp->next; //得到要删除节点得地址
Node<T>*t1 = temp->next; //得到要删除节点得地址
Node<T>*t2 = t1->next; //得到要删除节点得下一个节点地址
temp->next = t2; //链接前后节点
T temp2 = p->data; //返回要删除得数据到主函数
delete p; //释放节点
t1 = NULL;
return temp2; //返回要删除得数据到主函数
length1--; //长度减1
}
下面给出我之前写得源码
#include <iostream>
#include <string>
using namespace std; //泛型链表
template <class T>
struct Node{
T data;
Node<T> *next;
};
template <class T>
class linklist{
private:
Node<T> * Head;
int length1;
public:
linklist();
~linklist();
void adddate(T Data); //尾插函数
bool insertdat(T Data,int pos); //插入函数
T deletedat(int pos); //删除函数 ,会返回删除值
void displaylist(); //显示函数
int howlongitis(); //返回链表得长度
void fadddata(T e); //头插函数
void linkcombine(linklist*s1,linklist*s2);//合表函数
};
template <class T>
linklist<T>::linklist(){
Head = new Node<T>;
Head->next = NULL;
length1 = 0;
}
template <class T>
void linklist<T>::adddate(T Data)
{
Node<T> *p = new Node<T>;
p->data = Data;
p->next = NULL;
Node<T>*p1 = Head;
while(p1->next!=NULL){
p1 = p1->next;
}
p1->next =p ;
length1++;
}
template <class T>
void linklist<T>::displaylist(){
Node<T>*temp = Head->next;
while(temp!=NULL)
{
cout<<temp->data<<'\n'<<endl;
temp = temp->next;
}
}
template <class T>
void linklist<T>::fadddata(T e) //头插方法
{
Node<T>*temp = new Node<T>; //开辟新节点
temp->data = e; //保存数据
Node<T>*p1 = Head; //建立链接
temp->next = p1->next;
p1->next = temp;
length1++;
}
template <class T>
void linklist<T>::linkcombine(linklist*s1,linklist*s2)
{
Node<T>*p = s1->Head;
Node<T>*p2 = s2->Head->next;
while(p->next!=NULL)
{
p = p->next;
}
p->next = p2;
s1->length1+=s2->length1;
}
template <class T>
linklist<T>::~linklist()
{
Node<T>*temp = NULL;
Node<T>*p = Head->next;
while(p!=NULL){
temp = p->next;
delete p;
p = temp;
}
delete temp;
temp = NULL;
delete Head;
Head = NULL;
cout<<"................."<<endl;
length1 = 0;
}
template <class T>
int linklist<T>::howlongitis()
{
return length1;
}
template <class T>
T linklist<T>::deletedat(int pos){
if(pos>length1-1||pos<1)return 0;
Node<T>*temp = Head;
int k = 0;
while(k<pos-1)
{
temp = temp->next;
k++;
}
Node<T>*p = temp->next;
Node<T>*t1 = temp->next;
Node<T>*t2 = t1->next;
temp->next = t2;
T temp2 = p->data;
delete p;
return temp2;
length1--;
}
template <class T>
bool linklist<T>::insertdat(T Data,int pos)
{
if(pos>length1-1||pos<1)return false;
Node<T>*temp = Head;
int k = 0;
while(k<pos-1){
temp = temp->next;
k++;
}
Node<T>*tempneichun = new Node<T>;
tempneichun->data = Data;
tempneichun->next = temp->next;
temp->next = tempneichun;
length1++;
return true;
}
int main()
{
linklist<string>*l1 = new linklist<string>;
l1->fadddata("456");
l1->fadddata("789");
l1->fadddata("123");
l1->displaylist();
linklist<int>*o2 = new linklist<int>;
o2->adddate(9);
o2->adddate(8);
o2->adddate(7);
o2->displaylist();
int i = o2->deletedat(2);
cout<<"...."<<i<<endl;
l1->insertdat("sadweq",2);
l1->displaylist();
}
现在终于写完了,哈哈哈,对这些简单数据结构得了解可以加深对它得印象,是去了解其他更高级高层结构的基础,
希望这两篇文章对读者有帮助。