zoukankan      html  css  js  c++  java
  • 线性表的顺序存储——静态顺序表和动态顺序表的实现

    1,本文目标:

      1,完成 StaticList 类的具体实现;

      2,完成 DynamicList 类的具体实现;

    2,StaticList 设计要点:

           1,类模板:

                  1,使用原生数组作为顺序存储空间;

                  2,使用模板参数决定数组大小;

                       

    3,StaticList 的实现:

     1 #ifndef STATICLIST_H
     2 #define STATICLIST_H
     3 
     4 #include "SeqList.h"
     5 
     6 namespace DTLib
     7 {
     8 
     9 template <typename T, int N>
    10 class StaticList : public SeqList<T>
    11 {
    12 protected:
    13    T m_space[N];  // 顺序存储空间, N 为模板参数,静态定义的一个顺序存储空间,这就是 Static 的含义;
    14 
    15 public:
    16     StaticList()  // 指定父类成员的具体值;父类先默认初始化,然后子类再初始化继承而来的成员变量,各自初始化各自的成员变量;
    17     {
    18         this->m_array = m_space;
    19         this->m_length = 0;
    20    }
    21 
    22     int capacity() const
    23     {
    24         return N;
    25     }
    26 };
    27 
    28 }
     

    4,StaticList 类模板测试代码:
     1 #include <iostream>
     2 #include "StaticList.h"
     3 
     4 using namespace std;
     5 using namespace DTLib;
     6 
     7 int main()
     8 {
     9    StaticList<int, 5> l;
    10 
    11     for(int i=0; i<l.capacity(); i++)
    12     {
    13         l.insert(0, i);
    14    }
    15 
    16     for(int i=0; i<l.length(); i++)
    17     {
    18         cout << l[i] << endl;
    19    }
    20 
    21     l[0] *= l[0];
    22     for(int i=0; i<l.length(); i++)
    23     {
    24         cout << l[i] << endl;
    25    }
    26 
    27     try
    28     {
    29         l[5] = 5;
    30     }
    31     catch(const Exception& e)
    32     {
    33         cout << e.message() << endl;
    34         cout << e.location() << endl;
    35    }
    36 
    37     return 0;
    38 }

    5,DynamicList 设计要点(比 StaticList 复杂的多就是复杂在 Dynamic 上面):

           1,类模板:

                  1,申请连续堆空间(这里就是 Dynamic 含义)作为顺序存储空间;

                  2,动态设置(这里就是 Dynamic 含义)顺序存储空间的大小(觉着当前存储空间太大或太小了);

                  3,保证重置顺序存储空间时的异常安全性;

                         1,函数异常安全的概念:

                                1,不泄漏任何资源;

                                2,不允许破坏数据;

                         2,函数异常安全的基本保证:

                                1,如果一场被抛出:

                                       1,对象内任何成员任然能保持有效状态;

                                       2,没有数据的破坏及资源泄漏;

    6,DynamicList 设计要点:

         

    7,  DynamicList 的实现:

     1 #ifndef DYNAMICLIST_H
     2 #define DYNAMICLIST_H
     3 
     4 #include "SeqList.h"
     5 #include "Exception.h"
     6 
     7 namespace DTLib
     8 {
     9 template <typename T>
    10 class DynamicList : public SeqList<T>
    11 {
    12 protected:
    13    int m_capacity;   //顺序存储空间的大小
    14 
    15 public:
    16     DynamicList(int capacity)    //申请顺序存储空间
    17     {
    18         this->m_array = new T[capacity];
    19         if( this->m_array != NULL )
    20         {
    21             this->m_length = 0;
    22             this->m_capacity = capacity;
    23         }
    24         else
    25         {
    26             THROW_EXCEPTION(NoEnoughMemoryException, "No menory to create DynamicList object ...");
    27         }
    28    }
    29 
    30     int capacity() const
    31     {
    32         return m_capacity;
    33    }
    34 
    35     /* 重置顺序存储空间的大小,觉着当前存储空间太大或太小了,要重置 */
    36     void resize(int capacity)
    37     {
    38         if( m_capacity != capacity )
    39         {
    40             T* array = new T[capacity];    // 不用this->m_array是为了保证 this->m_array 指向原来的空间,以便下面的 for 循环的赋值操作;
    41 
    42             if( array != NULL )
    43             {
    44                 int length = (this->m_length < capacity ? this->m_length : capacity);
    45 
    46                 for( int i=0; i<length; i++ )    // 保证数据结构没有丢失,所以要让 m_array 还是指向原来的堆空间,当然这里数组也可以自己给自己赋值;
    47                 {
    48                     array[i] = this-> m_array[i];   // 这里可能发生异常,当发生异常的时候,三个成员变量值没有任何改变,线性表依然合法可用,只不过 array 指向的堆空间将会发生泄漏,但是对于 resize() 函数是无法顾全的,因为 array 里面存储的是 T 的泛指类型,这个泛指类型赋值操作符有可能被重载,如果重载里面是有错的,有异常的,这里我们就不能顾全了,如果在这里发生了异常,则就是泛指类型 T 导致的,也就是第三方工程导致的; 因为是泛指类型,这里的赋值可能由第三方工程师发生异常,不在考虑范围;如果发生异常,这里的 resize 保持不更改,但是会造成 array 指向的堆空间内存泄露;
    49                 }
    50 
    51                 T* temp = this->m_array;    // 是为了在下面删除之前的堆空间,如//果直接 delete[] this->m_array 则会发生异常不安全;
    52 
    53                 this->m_array = array;      //是为了使 resize 函数有效,这里类似//于构造函数,这三条语句不会发生异常;
    54                 this->m_length = length;
    55                 this->m_capacity = capacity;
    56 
    57                 delete[] temp;    // 在这里才删除是为了异常安全;因为泛指类型可//能是类类型,在delete[]时候就可能触发析构函数进而由于某种原因发生异常,这样就会发生异常返回了,也就不能保证上面三条语句执行,也就不能保证resize函数的有效了,则当前的线性表不能保证合法可用;则如果发生异常,这个线性表不可用,也就不是异常安全的了;这里这个函数是异常安全的,即便发生了异常,然后异常返回,但是三个成员变量的值已经合法,则当前线性表对象也是合法可用的;
    58             }
    59             else
    60             {
    61                 THROW_EXCEPTION(NoEnoughMemoryException, "No enough to resize DynamicList object ...");
    62             }
    63         }
    64    }
    65 
    66     ~DynamicList()
    67     {
    68         delete[] this->m_array;
    69     }
    70 };
    71 
    72 }
    73 
    74 #endif // DYNAMICLIST_H

    8,DynamicList 实现的测试代码:

     1 #include <iostream>
     2 #include "DynamicList.h"
     3 
     4 using namespace std;
     5 using namespace DTLib;
     6 
     7 int main()
     8 {
     9    DynamicList<int> l(5);
    10 
    11     for(int i=0; i<l.capacity(); i++)
    12     {
    13         l.insert(0, i);
    14    }
    15 
    16     for(int i=0; i<l.length(); i++)
    17     {
    18         cout << l[i] << endl;
    19    }
    20 
    21    l[0] *= l[0];
    22 
    23     for(int i=0; i<l.length(); i++)
    24     {
    25         cout << l[i] << endl;
    26    }
    27 
    28     try
    29     {
    30         l[5] = 5;
    31     }
    32     catch(const Exception& e)
    33     {
    34         cout << e.message() << endl;
    35         cout << e.location() << endl;
    36 
    37         l.resize(10);
    38         l.insert(5, 50);
    39    }
    40 
    41    l[5] = 5;
    42 
    43     for(int i=0; i<l.length(); i++)
    44     {
    45         cout << l[i] << endl;
    46    }
    47 
    48    l.resize(3);
    49 
    50    for(int i=0; i<l.length(); i++)
    51     {
    52         cout << l[i] << endl;
    53    }
    54 
    55     return 0;
    56 }

          

    9,是否可以将 DynamicList 作为 StaticList 的子类实现:

           1,不可以,反之也不可以;

           2,因为这两个类对于顺序存储空间的指定没有任何的关系,所以在类层次中位于同一层;

          

    10,小结:

           1,StaticList 通过模板参数定义顺序存储空间;

           2,DynamicList 通过动态内存申请定义顺序存储空间;

           3,DynamicList 通过动态重置顺序存储空间的大小;

           4,DynamicList 中的 resize() 函数实现需要保证异常安全;

  • 相关阅读:
    天翼网关获取超级密码
    Wirte-up:攻防世界Web解题过程新手区01-06
    F#周报2019年第12期
    F#周报2019年第11期
    F#周报2019年第10期
    F#周报2019年第9期
    F#周报2019年第8期
    F#周报2019年第7期
    ML.NET 0.10特性简介
    F#周报2019年第6期
  • 原文地址:https://www.cnblogs.com/dishengAndziyu/p/10921528.html
Copyright © 2011-2022 走看看