數(shù)據(jù)結(jié)構(gòu)(三)——基于順序存儲結(jié)構(gòu)的線性表

數(shù)據(jù)結(jié)構(gòu)(三)——基于順序存儲結(jié)構(gòu)的線性表

一、基于順序存儲結(jié)構(gòu)的線性表實現(xiàn)

1、順序存儲的定義

    線性表的順序存儲結(jié)構(gòu)是用一段地址連續(xù)的存儲單元依次存儲線性表中的數(shù)據(jù)元素。

數(shù)據(jù)結(jié)構(gòu)(三)——基于順序存儲結(jié)構(gòu)的線性表

十年的藍田網(wǎng)站建設(shè)經(jīng)驗,針對設(shè)計、前端、開發(fā)、售后、文案、推廣等六對一服務(wù),響應(yīng)快,48小時及時工作處理。全網(wǎng)整合營銷推廣的優(yōu)勢是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動調(diào)整藍田建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計,從而大程度地提升瀏覽體驗。創(chuàng)新互聯(lián)從事“藍田網(wǎng)站設(shè)計”,“藍田網(wǎng)站推廣”以來,每個客戶項目都認(rèn)真落實執(zhí)行。

2、順序存儲結(jié)構(gòu)的操作

    使用一維數(shù)組實現(xiàn)順序存儲結(jié)構(gòu)。
template <typename T>
class SeqList:public List<T>
{
protected:
  T* m_array;//順序存儲空間
  int m_length;//當(dāng)前線性表的長度
};
    一維順序存儲結(jié)構(gòu)可以是原生數(shù)組或是動態(tài)分配的空間。因此,根據(jù)空間分配的不同,分為靜態(tài)線性表和動態(tài)線性表。

(1)元素的獲取
順序存儲結(jié)構(gòu)的元素獲取操作:
A、判斷目標(biāo)位置是否合法
B、將目標(biāo)位置作為數(shù)組下標(biāo)獲取元素

bool get(int index, T& value)
{
  //判斷目標(biāo)位置是否合法
  bool ret = (0 <= index) && (index < m_length);
  if(ret)
  {
      //將目標(biāo)位置作為下標(biāo)獲取元素
      value = m_array[index];
  }
  return ret;
}

(2)元素的插入操作
順序存儲結(jié)構(gòu)的元素插入操作:
A、判斷目標(biāo)位置是否合法
B、將目標(biāo)位置后的所有元素向后移一位
C、將新元素插入目標(biāo)位置
D、線性表長度增加1

bool insert(int index, const T& value)
{
  //判斷目標(biāo)位置是否合法
  bool ret = (0 <= index) && (index <= m_length);
  ret = ret && ((m_length + 1) <= capacity());
  if(ret)
  {
      //將目標(biāo)位置后的所有元素后移一個位置
      for(int i = m_length -1; index <= i; i--)
      {
          m_array[i+1] = m_array[i];
      }
      //將新元素插入到目標(biāo)位置
      m_array[index] = value;
      //線性表長度加1
      m_length++;
  }
  return ret;
}

(3)元素的刪除操作
順序存儲結(jié)構(gòu)的元素刪除操作:
A、判斷目標(biāo)位置是否合法
B、將目標(biāo)位置后的所有元素前移一個位置
C、線性表長度減1

bool remove(int index)
{
  //判斷目標(biāo)位置是否合法
  bool ret = (0 <= index) && (index < m_length);
  if(ret)
  {
      //將目標(biāo)位置后的所有元素前移一位
      for(int i = index; i < m_length-1; i++)
      {
          m_array[i] = m_array[i+1];
      }
      //將線性表長度減1
      m_length--;
  }
  return ret;
}

(4)元素值的修改
順序存儲結(jié)構(gòu)中元素值的修改:
A、判斷目標(biāo)位置是否合法
B、修改目標(biāo)位置元素的值

bool set(int index, const T& value)
{
  //判斷目標(biāo)位置是否合法
  bool ret = (0 <= index) && (index < m_length);
  if(ret)
  {
      //修改目標(biāo)位置元素的值
      m_array[index] = value;
  }
  return ret;
}

(5)線性表長度的獲取
順序存儲結(jié)構(gòu)線性表的長度獲取

int length()const
{
  //線性表長度
  return m_length;
}

(6)線性表的清空

void clear()
{
  //清空線性表
  m_length = 0;
}

(7)[]操作符重載

//[]操作符重載
T& operator[](int index)
{
  //判斷目標(biāo)位置是否合法
  if((0 <= index) && (index < m_length))
  {
      //返回下標(biāo)相應(yīng)的元素
      return m_array[index];
  }
  else
  {
      THROW_EXCEPTION(IndexOutOfBoudsException, "Paramenter index is invalid...");
  }
}
//const對象的[]重載
T operator[](int index)const
{
  //轉(zhuǎn)換為非const對象后使用[]操作
  return (const_cast<SeqList<T>&>(*this))[index];
}

(8)順序存儲結(jié)構(gòu)空間的大小
virtual int capacity()const = 0;
由于存儲空間在子類分配,因此為純虛函數(shù)。

3、順序存儲結(jié)構(gòu)的抽象實現(xiàn)

 template <typename T>
  class SeqList:public List<T>
  {
  public:
    bool insert(int index, const T& value)
    {
      //判斷目標(biāo)位置是否合法
      bool ret = (0 <= index) && (index <= m_length);
      ret = ret && ((m_length + 1) <= capacity());
      if(ret)
      {
          //將目標(biāo)位置后的所有元素后移一個位置
          for(int i = m_length -1; index <= i; i--)
          {
              m_array[i+1] = m_array[i];
          }
          //將新元素插入到目標(biāo)位置
          m_array[index] = value;
          //線性表長度加1
          m_length++;
      }
      return ret;
    }
    bool remove(int index)
    {
      //判斷目標(biāo)位置是否合法
      bool ret = (0 <= index) && (index < m_length);
      if(ret)
      {
          //將目標(biāo)位置后的所有元素前移一位
          for(int i = index; i < m_length-1; i++)
          {
              m_array[i] = m_array[i+1];
          }
          //將線性表長度減1
          m_length--;
      }
      return ret;
    }
    bool set(int index, const T& value)
    {
      //判斷目標(biāo)位置是否合法
      bool ret = (0 <= index) && (index < m_length);
      if(ret)
      {
          //修改目標(biāo)位置元素的值
          m_array[index] = value;
      }
      return ret;
    }
    bool get(int index, T& value)const
    {
      //判斷目標(biāo)位置是否合法
      bool ret = (0 <= index) && (index < m_length);
      if(ret)
      {
          //將目標(biāo)位置作為下標(biāo)獲取元素
          value = m_array[index];
      }
      return ret;
    }
    int length()const
    {
      //線性表長度
      return m_length;
    }
    void clear()
    {
      //清空線性表
      m_length = 0;
    }

    int find(const T& value)const
    {
        int ret = -1;
        //遍歷線性表
        for(int i = 0; i < m_length; i++)
        {
            //如果找到元素,退出循環(huán)
            if(m_array[i] == value)
            {
               ret = i;
               break;
            }
        }
        return ret;
    }

    //[]操作符重載
    T& operator[](int index)
    {
      //判斷目標(biāo)位置是否合法
      if((0 <= index) && (index < m_length))
      {
          //返回下標(biāo)相應(yīng)的元素
          return m_array[index];
      }
      else
      {
          THROW_EXCEPTION(IndexOutOfBoudsException, "Paramenter index is invalid...");
      }
    }
    //const對象的[]重載
    T operator[](int index)const
    {
      //轉(zhuǎn)換為非const對象后使用[]操作
      return (const_cast<SeqList<T>&>(*this))[index];
    }
    virtual int capacity()const = 0;

  protected:
    T* m_array;//順序存儲空間
    int m_length;//當(dāng)前線性表的長度
  };

4、順序存儲結(jié)構(gòu)中數(shù)據(jù)元素移動的技巧

    數(shù)據(jù)元素的前移:
    將后面的數(shù)據(jù)元素向前移動,需要先將前面的數(shù)據(jù)元素前移,依次移動,直到最后一個數(shù)據(jù)元素前移,一般用于刪除一個數(shù)據(jù)元素后將后面的數(shù)據(jù)元素前移。
  //將目標(biāo)位置后的所有元素前移一位
  for(int i = index; i < m_length-1; i++)
  {
      m_array[i] = m_array[i+1];
  }
    數(shù)據(jù)元素的后移:
    將前面的數(shù)據(jù)元素向后移動,需要先將最后的數(shù)據(jù)元素后移,依次移動,直到第i個數(shù)據(jù)元素被后移,一般用于插入一個新的數(shù)據(jù)元素,需要先將插入位置后的所有數(shù)據(jù)元素后移,在位置處放入新的數(shù)據(jù)元素。
  //將目標(biāo)位置后的所有元素后移一個位置
  for(int i = m_length -1; index <= i; i--)
  {
      m_array[i+1] = m_array[i];
  }

5、原生數(shù)組實現(xiàn)的線性表

    使用原生數(shù)組作為順序存儲空間,使用模板參數(shù)確定數(shù)組大小。
 template <typename T, int N>
  class StaticList:public SeqList<T>
  {
  public:
    StaticList()
    {
      this->m_array = m_space;//指定父類指針指向的空間
      this->m_length = 0;//設(shè)置初始長度
    }
    int capacity() const
    {
      return N;
    }
  protected:
    T m_space[N];//順序存儲空間,N為模板參數(shù)
  };
    需要父類的實現(xiàn)純虛函數(shù)capacity()。

6、動態(tài)分配空間實現(xiàn)的線性表

        使用動態(tài)申請的堆空間作為順序存儲空間,動態(tài)設(shè)置順序存儲空間的大小并確保重置順序存儲空間大小時的異常安全。

函數(shù)異常安全要求不泄漏任何資源,不允許破壞數(shù)據(jù)。為了確保異常安全,在異常拋出時,必須確保:
A、對象內(nèi)的任何成員仍然能保持有效狀態(tài)
B、沒有數(shù)據(jù)的破壞及資源泄漏。

template <typename T>
class DynamicList:public SeqList<T>
{
public:
  DynamicList(int capacity)
  {
    //申請動態(tài)空間
    this->m_array = new T[capacity];
    if(this->m_array)
      {
        this->m_length = 0;//初始長度
        this->m_capacity = capacity;//空間大小
      }
    else
      {
        THROW_EXCEPTION(NoEnoughMemoryException, "No enough memory...");
      }
  }
  int capacity() const
  {
    return m_capacity;
  }

  void resize(int capacity)
  {
    if(capacity != m_capacity)
      {
        T* array = new T[capacity];
        if(array)
          {
            int length = (this->length() < capacity ? this->length():capacity);
            for(int i = 0; i < length; i++)
              {
                array[i] = this->m_array[i];
                //如果拋出異常,原數(shù)組狀態(tài)沒有改變
              }
            T* temp = this->m_array;
            this->m_array = array;
            this->m_capacity = capacity;
            this->m_length = length;
            delete[] temp;
            //如果拋出異常,重置后的數(shù)組狀態(tài)已經(jīng)改變
          }
        else
          {
            THROW_EXCEPTION(NoEnoughMemoryException, "No enough memory...");
          }
      }
  }
  ~DynamicList()
  {
    delete[] this->m_array;//釋放申請的動態(tài)空間
  }
protected:
  int m_capacity;//順序存儲空間的大小
};

二、順序存儲結(jié)構(gòu)線性表的效率分析

1、順序存儲結(jié)構(gòu)線性表的時間復(fù)雜度分析

數(shù)據(jù)結(jié)構(gòu)(三)——基于順序存儲結(jié)構(gòu)的線性表

2、順序存儲結(jié)構(gòu)線性表的效率分析

順序存儲結(jié)構(gòu)線性表的插入和刪除操作的時間復(fù)雜度都是O(n),但是由于插入和刪除操作都會涉及到線性表中數(shù)據(jù)元素的移動,因此會頻繁涉及拷貝構(gòu)造函數(shù)和賦值操作符的調(diào)用,如果數(shù)據(jù)元素對象內(nèi)部的資源較多,對象間的復(fù)制、賦值將是非常耗時的,同時由于線性表是泛型模板,無法確定實際實例化的對象類型是否是占有資源的類類型,因此需要禁用拷貝構(gòu)造函數(shù)和賦值操作符,禁用的方式只需要將拷貝構(gòu)造函數(shù)和賦值操作符聲明為protected即可。

template <typename T>
class List:public Object
{
protected:
  List(const List<T>& other);
  List<T>& operator=(const List<T>& other);
public:
  List(){}
  virtual bool insert(int index, const T& value) = 0;
  virtual bool remove(int index) = 0;
  virtual bool set(int index, const T& value) = 0;
  virtual bool get(int index, T& value) = 0;
  virtual int length()const = 0;
  virtual void clear() = 0;
};

3、順序存儲結(jié)構(gòu)線性表的缺陷

順序存儲結(jié)構(gòu)線性表重載了[]操作符,因此可以使用[]操作符訪問順序存儲結(jié)構(gòu)線性表中的元素。但是線性表中必須存在要訪問的元素,即先插入元素才能使用[]操作符訪問元素。

三、數(shù)組類的工程實現(xiàn)

1、數(shù)組類的抽象實現(xiàn)

    要創(chuàng)建一個數(shù)組類取代原生數(shù)組,數(shù)組類需要避免原生數(shù)組的缺陷:

A、數(shù)組類包含長度信息
B、數(shù)組類能夠主動發(fā)現(xiàn)越界訪問
數(shù)組類的設(shè)計如下:
A、抽象類模板,存儲空間的位置和大小由子類完成
B、重載數(shù)組操作符,判斷訪問下標(biāo)是否越界
C、提供數(shù)組長度的抽象訪問函數(shù)
D、拷貝構(gòu)造函數(shù)和賦值操作符需要在子類實現(xiàn)
數(shù)組的實現(xiàn):

template <typename T>
  class Array:public Object
  {
  public:
    virtual bool set(int index, const T& value)
    {
      bool ret = (0 <= index) && (index < length());
      if(ret)
      {
          m_array[index] = value;
      }
      return ret;
    }
    virtual bool get(int index, T& value)
    {
      bool ret = (0 <= index) && (index < length());
      if(ret)
      {
          value = m_array[index];
      }
      return ret;
    }

    T& operator[](int index)
    {
      if((0 <= index) && (index < length()))
      {
          return m_array[index];
      }
      else
      {
          THROW_EXCEPTION(IndexOutOfBoudsException, "Parameter index is valid...");
      }
    }
    T operator[](int index)const
    {
      return const_cast<T&>(*this)[index];
    }

    virtual int length()const = 0;
  protected:
    T* m_array;
  };
}

2、靜態(tài)數(shù)組類實現(xiàn)

指定原生數(shù)組作為數(shù)組類的存儲空間實現(xiàn)靜態(tài)數(shù)組類,使用模板參數(shù)指定數(shù)組大小,實現(xiàn)函數(shù)返回數(shù)組的長度,實現(xiàn)重載拷貝構(gòu)造函數(shù)和賦值操作符。

template &lt;typename T,int N&gt;
class StaticArray:public Array&lt;T&gt;
{
public:
StaticArray()
{
this-&gt;m_array = m_space;
}
//拷貝構(gòu)造函數(shù)
StaticArray(const StaticArray&lt;T,N&gt;& other)
{
this-&gt;m_array = m_space;
for(int i = 0; i &lt; N; i++)
{
m_space[i] = other.m_space[i];
}
}
//賦值操作符
StaticArray& operator=(const StaticArray&lt;T,N&gt;& other)
{
if(this != &other)
{
for(int i = 0; i&lt; N; i++)
{
m_space[i] = other.m_space[i];
}
}
return *this;
}
int length() const
{
return N;
}
protected:
T m_space[N];//存儲空間
};

3、動態(tài)分配數(shù)組實現(xiàn)

  使用動態(tài)分配的堆空間作為數(shù)組類的存儲空間實現(xiàn)動態(tài)分配數(shù)組類。
  類模板設(shè)計需要動態(tài)確定分配存儲空間的大小,實現(xiàn)函數(shù)返回數(shù)組大小,實現(xiàn)拷貝構(gòu)造函數(shù)和賦值操作符。

template &lt;typename T&gt;
class DynamicArray:public Array&lt;T&gt;
{
public:
//構(gòu)造函數(shù)
DynamicArray(int length)
{
this-&gt;m_array = new T[length];
if(this-&gt;m_array != NULL)
{
this-&gt;m_length = length;
}
else
{
THROW_EXCEPTION(NoEnoughMemoryException, "No enough memory...");
}
}
//拷貝構(gòu)造函數(shù)
DynamicArray(const DynamicArray&lt;T&gt;& other)
{
this-&gt;m_array = new T[other.m_length];
if(this-&gt;m_array != NULL)
{
this-&gt;m_length = other.m_length;
}
else
{
THROW_EXCEPTION(NoEnoughMemoryException, "No enough memory...");
}
}
//賦值操作符
DynamicArray&lt;T&gt;& operator=(const DynamicArray&lt;T&gt;& other)
{
if(this != &other)
{
T* array = new T[other.m_length];
if(array != NULL)
{
for(int i = 0; i &lt; other.m_length; i++)
{
array[i] = other.m_array[i];
}
T* temp = this-&gt;m_array;
this-&gt;m_array = array;
this-&gt;m_length = other.m_length;
delete[] temp;
}
else
{
THROW_EXCEPTION(NoEnoughMemoryException, "No enough memory...");
}
}
return *this;
}

int length()const
{
  return m_length;
}
//重置數(shù)組長度
void resize(int length)
{
  if(this->m_length != length)
  {
      T* array = new T[length];
      if(array != NULL)
      {
          int size = (length < this->m_length)?length:this->m_length;
          for(int i = 0; i < size; i++)
          {
              array[i] = this->m_array[i];
          }
          T* temp = this->m_array;
          this->m_array = array;
          this->m_length = length;
          delete[] temp;
      }
      else
      {
          THROW_EXCEPTION(NoEnoughMemoryException, "No enough memory...");
      }
  }
}
~DynamicArray()
{
  delete[] this->m_array;
}

protected:
int m_length;//數(shù)組長度
};

網(wǎng)站欄目:數(shù)據(jù)結(jié)構(gòu)(三)——基于順序存儲結(jié)構(gòu)的線性表
路徑分享:http://muchs.cn/article42/gppjhc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站建設(shè)、靜態(tài)網(wǎng)站、網(wǎng)站收錄網(wǎng)站導(dǎo)航、定制開發(fā)網(wǎng)頁設(shè)計公司

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

網(wǎng)站優(yōu)化排名