首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

刚看完数据结构,准备把主要数据结构实现一遍,下面是小弟我写的单链表,大家看看如何样?

2012-05-09 
刚看完数据结构,准备把主要数据结构实现一遍,下面是我写的单链表,大家看看怎么样??主要是想大家指出一下不

刚看完数据结构,准备把主要数据结构实现一遍,下面是我写的单链表,大家看看怎么样??
主要是想大家指出一下不合理的问题,需要注意的方面..不胜感激

C/C++ code
//MyList.h#ifndef MYLIST_H#define MYLIST_Htemplate<class T>class Node{    public:        friend bool operator==(const Node<T>& lhs,const Node<T>& rhs);        Node()        {            next=NULL;        }        Node(T rhs):val(rhs)        {            next=NULL;        }        T val;                    //结点的值        Node<T> *next;    //指向下一个结点    };//定义结点类template<class T>class List{    public:        List():head(NULL),length(0){}        void InitList();        //初始化链表        void DestoryList();        //销毁链表        void ClearList();        //清除链表元素        bool ListEmpty();        //判断链表是否为空        int ListLength();        //返回链表长度        bool GetElem(int i,Node<T>& elem);                    //返回链表里的第i个数据元素        bool PriorElem(const Node<T>& cur,Node<T>& elem);    //返回cur元素的前驱        bool NextElem(const Node<T>& cur,Node<T>& elem);    //返回cur元素的后继        bool ListInsert(int i,T val);                        //在链表里的第i个数据元素前插入元素elem        bool ListDelete(int i,Node<T>& elem);                //删除链表里的第i个数据元素,用elem返回        void PrintList();        //输出链表的元素    private:        Node<T> *head;            //指向链表头结点        int length;                //链表长度};//定义链表类#include "MyList.cpp"#endif


C/C++ code
//MyList.cpp#include "MyList.h"template<class T>bool operator==(const Node<T>& lhs,const Node<T>& rhs){    if(lhs.val==rhs.val)        return true;    else        return false;}template<class T>void List<T>::InitList()        //初始化链表{    head=new Node<T>();    }template<class T>void List<T>::DestoryList()        //销毁链表{    ClearList();    delete head;    head=NULL;}template<class T>void List<T>::ClearList()        //清除链表元素{    Node<T> del_val;    while(length>0)        ListDelete(1,del_val);}template<class T>bool List<T>::ListEmpty()        //判断链表是否为空{    if(head->next==NULL)        return true;    return false;}template<class T>int List<T>::ListLength()        //返回链表长度{    return length;}template<class T>bool List<T>::GetElem(int i,Node<T>& elem)        //返回链表里第i个数据元素{    if( i<1 || i>length )    {        return false;    }    Node<T>* p=head;    int cnt=0;    while(cnt<i)    {        p=p->next;        cnt++;    }    if(p)        elem=*p;    else        return false;    return true;}template<class T>bool List<T>::PriorElem(const Node<T>& cur,Node<T>& elem)        //返回cur的前驱{    Node<T>* p=head;    while(p!=NULL)    {        if(p->next)                                                //防止对空链表操作        {            if(*(p->next)==cur)            {                if(p!=head)                {                    elem=*p;                    return true;                }            }        }        p=p->next;    }    return false;}template<class T>bool List<T>::NextElem(const Node<T>& cur,Node<T>& elem)        //返回cur的后继{    Node<T>* p=head;    while(p->next!=NULL)    {        if(*p==cur)        {            elem=*(p->next);            return true;        }        p=p->next;    }    return false;}template<class T>bool List<T>::ListInsert(int i,T val)                    //在i位置之前插入数据元素elem{    if( i<1 || i>length+1 )    {        return false;    }    Node<T>* p=head;    int cnt=0;    while(cnt<i-1)                    //找到第i-1个位置    {        p=p->next;        cnt++;    }    if(p)    {        Node<T>* pElem=new Node<T>(val);        pElem->next=p->next;        p->next=pElem;        length++;        return true;    }    return false;}template<class T>bool List<T>::ListDelete(int i,Node<T>& elem)                    //删除第i个位置的元素{    if( length<1 || i<1 || i>length )    {        return false;    }    Node<T>* p=head;    Node<T>* pre=NULL;    int cnt=0;    while(cnt<i)    {        if(cnt==i-1)        //保存i-1位置元素的指针            pre=p;        p=p->next;        cnt++;    }    if(p && pre)    {        pre->next=p->next;        elem=*p;        delete p;        length--;        return true;    }    return false;}template<class T>void List<T>::PrintList()            //打印链表数据元素{    Node<T>* p=head;    while(p->next)    {        p=p->next;        cout<<p->val<<" ";    }} 



C/C++ code
//List.cpp 
#include <iostream>
#include "MyList.h"
using namespace std;

int main()
{
List <int> list;
list.InitList();
Node <int> del;
for(int i=1;i <=10;i++)
{
list.ListInsert(i,i);
}

cout < <"当前链表长度:" < <list.ListLength() < <endl;
cout < <"打印链表:" < <endl;
list.PrintList();

cout < <"\n" < <list.ListEmpty() < <endl;

if(list.ListDelete(1,del))
cout < <"正在删除:" < <del.val < <endl;

cout < <"当前链表长度:" < <list.ListLength() < <endl;
cout < <"打印链表:" < <endl;
list.PrintList();

Node <int> val(4);
Node <int> ret;
if(list.PriorElem(val,ret))
cout < <"\n前驱是:" < <ret.val < <endl;
if(list.NextElem(val,ret))
cout < <"后继是:" < <ret.val < <endl;

list.ClearList();
cout < <"当前链表长度:" < <list.ListLength() < <endl;


list.DestoryList();

return 0;
}


[解决办法]
楼主,我告诉你个秘密,你不要告诉别人啊!
CSDN上的所有高手看了你的代码,都会微微一笑,然后想起自己年轻的时候也经常犯傻。

我没笑,因为我还年轻。

因为本人没学过C++,没学过数据结构,没学过算法,没学过模板。
所以看到楼主竟然用模板实现链表,很佩服,很不服气,所以才来吹牛,我说的话楼主不要往心里去。

你写的很烂。

1.你想知道自己写的好不好,不如去和stl中的list比较一下。

如果第1条是废话。那么我就说点具体的。

2.为什么返回值是bool?也许你希望在某种情况下,判断操作有没有正确执行。但假如有很多步操作,我都要确保它们执行完成,那么我是不是要写很多的if,else?你把你写的链表给客户用,客户会因为你的链表而增加大量的冗余代码。

3.GetElem PriorElem NextElem , 这三个函数,以及所有有“返回值”的函数,都存在同样一个问题:客户必须知道你写的链表的内部节点的结构。一个很恰当的比方:你去超市买东西,进去的时候,你把你的手提包存在存包点,买完东西回来发现,你必须把一个特定的“盒子”,交给存包点,存包点把你的包放进盒子,在把盒子交给你。而且更加疯狂的是,这个盒子还必须“自备”。你希望客户知道你的链表的节点的结构,这样方便你返回,方便你查找,但是客户可不这么认为,客户认为,我存进去的数据是什么,那么返回的就是什么,存int型数据,返回的竟然是一个Node类型的数据?思维怪异。

4.为什么初始化的时候要加一个节点进去?为什么链表中有一个节点,而链表的长度依然为0?如果是头节点,那么为什么需要头节点?数据结构的书可不要学死了。

几点建议:
将list设为node的友元,node的所有数据成员,所有成员函数均为private。
该返回bool的返回bool,该返回元素值的返回元素值,像insert某某,不如干脆不返回。
如果希望某些操作有某些保障,那么不要用返回值来确定操作是否完成,而应该在操作没有正确完成时---抛出异常。(and stay away from exit()!!!!!)
将没必要的诸如:GetHead, GetTail之类完全删除,因为这个操作竟然返回私有成员的地址,你主动破坏封装?
多注意细节没什么不好,多注意效率没什么不好,但是你首先要把事情做对,然后再做好。

你的list的接口我都看了,具体实现我只看了一点点。因为我觉得你很认真好学,所以我才说上面一堆废话。你用模板写,狠好,我100多号同学,知道什么是模板的寥寥无几,像我就啥都不懂,更别说用模板写容器了。所以,你要做业内人士,就一定要走出“思维怪异”的怪圈,拥抱面向对象思想。
[解决办法]
两句话送给楼主:
一句是我学长说的:“C++,MFC,数据结构,算法,这些都是基础呀。”
一句是侯捷说的:“勿在浮沙筑高台。”
[解决办法]
如果需要用带头节点的链表,头节点不要去new,直接把Node<T> *head;改成Node<T> head;。如果需要带尾节点的链表,也作同样的修改。
不要让你的公开函数返回T类型和基本类型(bool,int)之外的任何类型,因为那些类型跟这个类的使用者无关,只跟设计者也就是你有关。
不要把只在链表内部使用的Node类型定义在跟List平等的地位上,它只是在List内部使用,定义成List的一个私有的内部类型,或者象23楼说的那样也好。

另外,搞笑的是,你的Node的成员既然都是public的,为什么还会在里面有个friend声明呢?你可能根本没有去想friend是干什么的。

祝你进步!

[解决办法]
LZ的编程风格与注释的好习惯还是十分值得称赞的,23楼的建议还是挺中肯的。用面向对象的思想编程,没有数据抽象的过程应该不能称的上是面向对象。没有很好的进行数据抽象,类的封装不合理,这可能是一个漫长的过程,另关键字friend用的让人摸不着头脑,先搞明白自己想要实现的功能。祝LZ进步。

热点排行