【指针】基于单向链表的list(待改进)

Description:

 请实现以下基于单向链表的list类

enum Error_code

{

         success,

         underflow,

         overflow

};

template <class List_entry>

struct Node

{

         List_entry entry;

         Node<List_entry> *next;

};

 

template <class List_entry>

class MyList

{

public:

         MyList();

         ~MyList();

         // 拷贝构造函数和赋值运算符重载,注意深拷贝与浅拷贝的差异

         MyList(const MyList<List_entry> &copy);

         void operator =(const MyList<List_entry> &copy);

 

         // 清空list

         void clear();

         // 判断list是否为空

         bool empty() const;

         // 判断list是否已满

         bool full() const;

         // 获取list的元素数量

         int size() const;

         // 在第position个位置插入值为entry的元素,如果position为0则插入在链表头,依次类推

         // 若position < 0 或者 position > count,则返回underflow

         Error_code insert(int position, const List_entry &entry);

         // 删除第position个位置的元素,并将该元素的值保存在entry中

         // 若position < 0 或者 position >= count,则返回underflow

         Error_code remove(int position, List_entry &entry);

         // 获取第position个位置的元素,保存在entry中

         // 若position < 0 或者 position >= count,则返回underflow

         Error_code retrieve(int position, List_entry &entry) const;

         // 将第position个位置的元素替换为entry

         // 若position < 0 或者 position >= count,则返回underflow

         Error_code replace(int position, const List_entry &entry);

         // 用visit函数遍历list内所有的元素

         void traverse(void (*visit)(List_entry &));

protected:

         int count;                                                                          // 记录list内元素数量

         Node<List_entry> *head;                                         // 链表头指针

         mutable int curPosition;                                   // current指针的位置编号

         mutable Node<List_entry> *current;                 // current指针

 

         // 设置current指针的位置,指向第position个位置

         void setPosition(int position) const;

};
View Code


 

解题思路:

首先,对于一个普通的list来说,最基本的不外乎增删查改,其他的赋值或清空都可以通过这4种操作来完成,写好这主要的4个函数就好了。

另外,注意到这个MyList类提供了current这个指针。

1.insert(增):

  position合理的情况下,若position为队头,则直接将position的next指向head,head再更新;

      若position不是队头,position的next指向下一个位置,前一个节点的next指向position;

2.remove(删):

 position合理的情况下,若删除位置为队头,head=head->next,并注意将原本的队头delete;

         若删除位置不是队头,则前节点直接指向potision的后节点,position节点delete即可;

3.retrieve(查):

      调用setPosition来查找目标,并返回值即可;

4.replace(改):

      调用setPosition查找目标,并修改值;

5.赋值运算:

    不断从copy中读取(retrieve),并插入(insert)到MyList中;

6.clear(清空):

  可以不断调用remove来清空,这里代码我就直接用for循环来删除啦。

7.setPosition:是通过current指针来提高平均时间复杂度的一个函数;

        当position比current大时,current只需向后更新;

        若position小于current时,则current先更新为head,然后再更新到position位置

实现代码:

enum Error_code//错误信息
{
  success,
  underflow,
  overflow
};

template<class List_entry>
struct Node
{
  List_entry entry;
  Node<List_entry>*next;
};

template<class List_entry>
class MyList
{
  public:
     MyList() {
       curPosition = count = 0;
       head = current = 0;
     }
       
     ~MyList() {
       clear();
     }

     // 拷贝构造函数和赋值运算符重载
     MyList(const MyList<List_entry> &copy) {
      curPosition = count = 0;//拷贝构造函数一定要对数据成员进行初始化!
      head = current = 0;
          *this = copy;
     }
     void operator=(const MyList<List_entry> &copy) {
          clear();
          List_entry entry;
          for (count = 0; count < copy.size(); ) {
              copy.retrieve(count, entry);//读取
              insert(count, entry);       //增加
          }
          setPosition(copy.curPosition);
     }

      // 清空list
     void clear() {
         Node<List_entry>* tmp1 = head;
         Node<List_entry>* tmp2;
         while (tmp1 != 0) {
         tmp2 = tmp1->next;
             delete tmp1;
         tmp1 = tmp2;
         }
         count = curPosition = 0;
         current = head = 0;
     }
    // 判断list是否为空
     bool empty() const {
          if (count == 0)
             return true;
          else
             return false;
     }
     // 判断list是否已满
     bool full() const {
          return false;
     }
        // 获取list的元素数量
     int size() const {
          return count;
     }

     // 在第position个位置插入值为entry的元素,如果position为0则插入在链表头,依次类推
         // 若position < 0 或者 position > count,则返回underflow
     Error_code insert(int position, const List_entry& entry) {//
                if (position < 0 || position > count)
                    return underflow;
                else
                {
                  count++;
                  Node<List_entry>* tmp = new Node<List_entry>;
                  tmp->entry = entry;
                  if (position == 0) {
                       if (head == 0) {//在队头增加
                          tmp->next = head;
                          head = tmp;
                        }
                       current = head;
                   } else {         //在list中间增加
                     setPosition(position-1);
                     tmp->next = current->next;
                     current->next = tmp;
                     current = tmp;
                     curPosition++;
                   }
                }
              return success;
      }

      // 删除第position个位置的元素,并将该元素的值保存在entry中
         // 若position < 0 或者 position >= count,则返回underflow
     Error_code remove(int position, List_entry &entry) {
        if (position < 0 || position >= count)
                   return underflow;
                 else {
                   count--;
                   if (position == 0) //删队头
                      {
                        Node<List_entry>* tmp= head;
            entry = tmp->entry;
                        head= head->next;
                        delete tmp;
                        current = head;
                        curPosition = 0;
                    } else {         //删除list中的元素
                      setPosition(position-1);
                      Node<List_entry>* tmp = current->next;
                      entry = tmp->entry;
                      current->next = tmp->next;
                      delete tmp;
                      }
          return success;
                 }
     }

          // 获取第position个位置的元素,保存在entry中
         // 若position < 0 或者 position >= count,则返回underflow
     Error_code retrieve(int position, List_entry& entry) const {
        if (position < 0 || position >= count)
                   return underflow;
        else
        {
          setPosition(position);
                  entry = current->entry;
          return success;
        }
    }

    // 将第position个位置的元素替换为entry
         // 若position < 0 或者 position >= count,则返回underflow
     Error_code replace(int position, const List_entry &entry) {
        if (position < 0 || position >= count)
            return underflow;
        else
        {
          setPosition(position);
          current->entry = entry;
        return success;
        }
    }
     // 用visit函数遍历list内所有的元素
     void traverse(void(*visit)(List_entry&)) {
         Node<List_entry>* tmp = head;
         for (int i = 0; i < count; i++) {
             (*visit)(tmp->entry);
             tmp = tmp ->next;
         }
     }
  protected:
     int count; // 记录list内元素数量
     Node<List_entry>*head;  // 链表头指针
     mutable int curPosition;  // current指针的位置编号
     mutable Node<List_entry>* current;    // current指针
    // 设置current指针的位置,指向第position个位置
     void setPosition(int position) const {
          if (position >= curPosition)
             for (; curPosition < position; curPosition++)
                  current = current->next;
          else
             for (current = head, curPosition = 0; curPosition < position; curPosition++)
                 current = current->next;
     }
};     
View Code


进一步思考:

这里,我们不妨再看看,常常runtime error让我们头疼的链表问题是非法访问内存地址,

比如,队列为空时,head==0,但我们常常不小心访问了head->next,或者企图访问head的前节点

而这个情况常常发生在增删的情况中,那我们可以使list初始情况就为非空

令head永远指向一个空节点node(node->next=0),初始情况curPosition=-1,

这样每次插入新元素,不管新元素的位置在哪里,都不用再做特殊判断,直接更新position前节点的next即可

也就是插入新元素只有以下这两种情况:

         和                  

而这两种情况的实现代码都是:setPosition(position-1);

              tmp->next = current->next;

              current->next = tmp;

每次删除新元素,也不用管是不是队头,直接更新前节点的next即可

也就是删除新元素只有以下这两种情况:

 而这两种情况的实现代码都是:Node<List_entry>* tmp = current->next; 

               current->next = tmp->next;

              delete tmp;

实现代码:

/*有空队头的情况*/
enum Error_code//错误信息
{
  success,
  underflow,
  overflow
};

template<class List_entry>
struct Node
{
  List_entry entry;
  Node<List_entry>*next;
};

template<class List_entry>
class MyList
{
  public:
     MyList() {
        count = 0;
    curPosition = -1;
    head = current = new Node<List_entry>;
    head->next = 0;
     }

     ~MyList() {
    clear();
    delete head;
    head = current = 0;
    count = curPosition = 0;
     }
     // 拷贝构造函数和赋值运算符重载
     MyList(const MyList<List_entry> &copy) {
          count = 0;//拷贝构造函数一定要对数据成员进行初始化!
          curPosition = -1;
          head = current = new Node<List_entry>;
          head->next = 0;
          *this = copy;
    }

     void operator=(const MyList<List_entry> &copy) {
          clear();
          List_entry entry;
      while(count < copy.size()) {
        copy.retrieve(count, entry);//读取
            insert(count, entry);//增加
      }
      setPosition(copy.curPosition);
    }
      // 清空list
    void clear() {
         Node<List_entry>* tmp1 = head->next;
         Node<List_entry>* tmp2;
         while (tmp1 != 0) {
         tmp2 = tmp1->next;
             delete tmp1;
         tmp1 = tmp2;
         }
         count = 0;
         current = head;
     head->next = 0;
     curPosition = -1;
     }
    // 判断list是否为空
     bool empty() const {
          if (count == 0)
             return true;
          else
             return false;
     }
     // 判断list是否已满
     bool full() const {
          return false;
     }
        // 获取list的元素数量
     int size() const {
          return count;
     }
     // 在第position个位置插入值为entry的元素,如果position为0则插入在链表头,依次类推
         // 若position < 0 或者 position > count,则返回underflow
     Error_code insert(int position, const List_entry& entry) {
                if (position < 0 || position > count)
                    return underflow;
                else
                {
                  Node<List_entry>* tmp = new Node<List_entry>;
                  tmp->entry = entry;
                  setPosition(position-1);
                  tmp->next = current->next;
                  current->next = tmp;
                  current = tmp;
                  curPosition++;
                  count++;
                }
              return success;
      }
      // 删除第position个位置的元素,并将该元素的值保存在entry中
         // 若position < 0 或者 position >= count,则返回underflow
     Error_code remove(int position, List_entry &entry) {
        if (position < 0 || position >= count)
                   return underflow;
                 else {
           setPosition(position-1);
                   Node<List_entry>* tmp = current->next;
                   entry = tmp->entry;
                   current->next = tmp->next;
                   delete tmp;
                   count--;
           return success;
                 }
     }
          // 获取第position个位置的元素,保存在entry中
         // 若position < 0 或者 position >= count,则返回underflow
     Error_code retrieve(int position, List_entry& entry) const {
        if (position < 0 || position >= count)
                   return underflow;
        else
        {
          setPosition(position);
                  entry = current->entry;
          return success;
        }
    }
    // 将第position个位置的元素替换为entry
         // 若position < 0 或者 position >= count,则返回underflow
     Error_code replace(int position, const List_entry &entry) {
        if (position < 0 || position >= count)
            return underflow;
        else
        {
          setPosition(position);
          current->entry = entry;
        return success;
        }
    }
     // 用visit函数遍历list内所有的元素
     void traverse(void(*visit)(List_entry&)) {
         Node<List_entry>* tmp = head->next;
         for (int i = 0; i < count; i++) {
             (*visit)(tmp->entry);
             tmp = tmp ->next;
         }
     }

  protected:
     int count;// 记录list内元素数量
     Node<List_entry>*head;// 链表头指针
     mutable int curPosition;// current指针的位置编号
     mutable Node<List_entry>* current;// current指针
    // 设置current指针的位置,指向第position个位置
     void setPosition(int position) const {  
          if (position >= curPosition)
             for (; curPosition < position; curPosition++)
                  current = current->next;
          else
             for (current = head, curPosition = -1; curPosition < position; curPosition++)
                 current = current->next;
     }
};
View Code

总结:

也许你觉得这不过是少了十几行代码,少了两段if语句,但下一篇,双向链表,我们能更进一步看见这种方法的安全性和便捷性。

原文地址:https://www.cnblogs.com/zengyh-1900/p/4067679.html