您的位置:首页 > 理论基础 > 数据结构算法

List数据结构的实现

2015-08-01 10:46 531 查看
这几天在学习数据结构(C++描述)的知识,为了把基础打的牢固一些,想想把一种数据结构自己动手写代码实现以下,感觉是个不错的方法。那样就不会只停留在会用的程度。首先整理一下要实现的山寨list要提供的接口。

push_back() 末端插入元素

back() 返回末端元素的值

push_front() 顶端插入元素

front() 返回顶端元素的值

find() 查找特定元素的地址

insert() 特定的位置插入元素

size() 返回list当中元素的个数

begin() 返回一个游标,指向顶端元素

end() 返回一个游标,指向末端元素

实现山寨list,底层的数据结构肯定选双向链表,在任何位置插入元素的复杂度都为o(1),双向链表是由一个个节点链接起来的,节点包括三个成员:指向后继节点的指针、指向前驱节点的指针、当前节点的节点值。先实现这个类:

template <typename T>
class dnode{
public:
T nodeValue;//节点值
dnode<T> *next;//后继节点
dnode<T> *prev;//前驱节点
dnode(const T& value=T()){
nodeValue=value;
next=NULL;
prev=NULL;
};//构造函数,初始化节点值、前驱和后继节点
};


然后将一个个节点串接起来就形成了双向链表,将双向链表的首位相接,就得到一个list,就像用一个个珠子串起来串成项链一样。实现miniList这个类:

#include "dnode.h"
#include <string>
using namespace std;
template <typename T>
class miniList{
public:
miniList();/*三个版本的构造函数
/第一个生成一个空list,第二个初始化list为n个item值的list
第三个用[first,last]初始化list*/
miniList(int n,const T& item=T());
miniList(T *first,T *last);
~miniList();//析构函数
/*游标的声明*/
class iterator{
public:
iterator();//构造函数,生成一个空游标
iterator(dnode<T> *p);//构造函数,将dnode类型的指针转换为游标
/*重载"=="和"!="运算符,比较两个游标所指的值*/
bool operator ==(const iterator& rhs) const;
bool operator !=(const iterator& rhs) const;
/*重载"*"运算符,返回游标所指的值*/
T& operator *();
/*重载"++"和"--"运算符,因为这两个运算符有前缀和后缀的形式,所以后缀运算符多加一个
int参数,好让编译器判断用户使用的是哪种形式。游标的本质其实还是指针,所以++或者--
只是让私有成员node成为自身的后继或者前驱*/
iterator& operator ++(){
node=node->next;
return *this;
};
iterator& operator ++(int){
iterator temp=*this;
node=node->next;
return temp;
};
iterator& operator --(){
node=node->prev;
return *this;
};
iterator& operator --(int){
iterator temp=*this;
node=node->prev;
return temp;
};
private:
//游标的本质还是指针,指针的类型就是实现list的基石--dnode
dnode<T> *node;
};
void push_back(const T& item);//在list末端插入值
T& back();//返回list末端的值
void push_front(const T& item);//在list顶端插入值
T& front();//返回list顶端的值
/*在固定的位置插入值,返回新的新节点的地址,因为dnode指针是对外不可见的,所以要和find函数搭配使用*/
dnode<T>* insert(const T& item,dnode<T> *curr);
dnode<T>* find(const T& item);//查找一个元素的位置,返回这个元素的指针
int size();//返回当前list的元素个数
typename miniList<T>::iterator begin();//返回一个游标对象,指向list的顶端值
typename miniList<T>::iterator end();//返回一个游标对象,指向list的末端值
private:
dnode<T> *header;//头结点
int listSize;//元素个数
};
template <typename T>//构造函数,生成一个空list,元素个数为0
miniList<T>::miniList(){
header=new dnode<T>;
listSize=0;
}
template <typename T>//构造函数,生个n个item元素的list
miniList<T>::miniList(int n,const T& item=T()){
header=new dnode<T>(item);
dnode<T> *temp;//存储n个item值的动态节点
dnode<T> *curr;//当前节点
curr=header;
unsigned int i;
for(i=0;i<n;i++){
temp=new dnode<T>(item);//生成一个节点
curr->next=temp;//当前节点的后继节点就是这个新生成的节点
temp->prev=curr;//新节点的前驱节点为当前节点
curr=temp;//更新当前节点,继续生成下一个节点
}
curr->next=header;//结束之后将当前节点的后继节点更新为头结点
header->prev=curr;//头结点的前驱节点为当前这个节点,这样整个list就串起来
listSize=n;//元素个数更新为n
}
template <typename T>
miniList<T>::miniList(T *first,T *last){
/*先计算出first到last这段地址的元素数,其他的与上面类似,
区别只是生成新节点时的节点值为当前地址中保存的值*/
int n=last-first;
header=new dnode<T>;
dnode<T> *temp;
dnode<T> *curr;
curr=header;
unsigned int i;
for(i=0;i<n;i++){
temp=new dnode<T>(*first);
curr->next=temp;
temp->prev=curr;
curr=temp;
first++;
}
curr->next=header;
header->prev=curr;
listSize=n;
}
template <typename T>//析构函数,遍历整个list,逐个释放内存
miniList<T>::~miniList(){
dnode<T> *curr;
curr=header->next;
while(curr!=header){
delete curr;
curr=curr->next;
}
delete header;
}
template <typename T>//在list的末端插入值
void miniList<T>::push_back(const T& item){
dnode<T> *temp,*curr;
temp=new dnode<T>(item);
if(listSize==0){//表示当前list中只有一个header
header->next=temp;
temp->next=header;
header->prev=temp;
temp->prev=header;
}else if(listSize>0){
//元素数不为0,在末端插入值其实就是在header前面插入值,因为list是串起来的环,先找到header的前驱
curr=header->prev;
//打开header的前驱和header,在中间插入新生成的temp
curr->next=temp;
temp->next=header;
header->prev=temp;
temp->prev=curr;
}
listSize++;
}
template <typename T>
T& miniList<T>::back(){
if(listSize>0)//元素个数不为0,返回末端元素的值,其实就是header前驱节点的值
return header->prev->nodeValue;
}
template <typename T>//在顶端和在末端插入元素的方法类似,区别只是在顶端插入值时,插入的位置为header和header后继节点的中间。
void miniList<T>::push_front(const T& item){
dnode<T> *curr,*temp;
temp=new dnode<T>(item);
if(listSize==0){
header->next=temp;
temp->prev=header;
temp->next=header;
header->prev=temp;
}else if(listSize>0){
curr=header->next;
header->next=temp;
temp->next=curr;
temp->prev=header;
curr->prev=temp;
}
listSize++;
}
template <typename T>
T& miniList<T>::front(){
if(listSize>0)//元素个数不为0,返回顶端元素,其实就是header后继节点的节点值
return header->next->nodeValue;
}
template <typename T>
int miniList<T>::size(){
return listSize;//返回当前元素的个数
}
template <typename T>//返回一个游标,指向顶端元素,
typename miniList<T>::iterator miniList<T>::begin(){
return iterator(header->next);//调用iterator的构造函数,将dnode类型的指针转换为游标
}
template <typename T>
typename miniList<T>::iterator miniList<T>::end(){
return iterator(header);//与begin函数类似,区别是end返回的游标指向list的header,而不是一个具体的元素
}
template <typename T>//在固定的位置插入一个值
dnode<T>* miniList<T>::insert(const T& item,dnode<T> *curr){
dnode<T> *tempNode,*tempPrev;
tempNode=new dnode<T>(item);//新生成一个节点
tempPrev=curr->prev;//找到插入位置的前驱节点

tempPrev->next=tempNode;//插入这个新节点
tempNode->next=curr;
curr->prev=tempNode;
tempNode->prev=tempPrev;
listSize++;
return tempNode;
}
template <typename T>//查找一个元素,返回它的地址,不在list当中则返回NULL
dnode<T>* miniList<T>::find(const T& item){
dnode<T> *temp=header->next;
//查找元素,直到找到该元素或者遍历完整个list
while(temp->nodeValue!=item&&temp!=header){
temp=temp->next;
}
if(temp!=header)//找到的该元素,返回它的地址
return temp;
return NULL;//遍历完整个list,说明不在list当中,返回NULL
}
template <typename T>//游标的两个构造函数,第一个生成一个空游标,第二个将dnode类型的指针转换为游标
miniList<T>::iterator::iterator(){
node=NULL;
}
template <typename T>
miniList<T>::iterator::iterator(dnode<T> *p){
node=p;
}
template <typename T>//重载的运算符,比较两个游标所指元素的元素值
bool miniList<T>::iterator::operator==(const iterator& rhs)const{
return node->nodeValue==rhs.node->nodeValue;
}
template <typename T>
bool miniList<T>::iterator::operator!=(const iterator& rhs)const{
return node->nodeValue!=rhs.node->nodeValue;
}
template <typename T>//重载的"*"运算符,返回游标所指元素的值
T& miniList<T>::iterator::operator*(){
return node->nodeValue;
}


测试一下能不能正常的工作:

void main(){
unsigned int i;
int a[]={1,6,2,5,6,7};
miniList<int> list1(a,a+6);
miniList<int>::iterator it;
dnode<int> *temp;
temp=list1.find(2);
list1.insert(3,temp);
list1.push_back(9);
it=list1.begin();
while(it!=list1.end()){
cout<<*it<<" ";
it++;
}
while(1);
}
先用数组初始化一个list,生成一个空游标,并用list的end函数初始化,找到2的地址,在2前面插入3,在末端插入9,最后输出list的全部元素,测试结果:



按照预定的方式运行了,由于想让代码看起来简洁,没有进行异常的捕捉,也假设测试输入都是正确的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  数据结构 List