一、線性表

一、線性表

線性表是一種抽象的數(shù)據(jù)類型,下面介紹幾種具體的線性表存儲(chǔ)結(jié)構(gòu)(即物理結(jié)構(gòu)):順序、鏈?zhǔn)胶挽o態(tài)鏈?zhǔn)健o(wú)論線性表采用哪種數(shù)據(jù)結(jié)構(gòu),她們的邏輯結(jié)構(gòu)是一樣的,都有以下性質(zhì):除第一個(gè)元素外,線性表中每個(gè)元素都有一個(gè)前驅(qū)元素;除最后一個(gè)元素外,線性表中每一個(gè)元素都有一個(gè)后繼元素。

實(shí)現(xiàn)

//線性表抽象類的定義
template<typename T>class AList
{
public:
  void ClearList();  //重置線性表為空表
  bool ListEmpty()const;  //若線性表為空表,則返回 true;否則返回 false
  int LocateElem(T e, bool(*eq) (T, T))const;
  //返回第一個(gè)與 e 滿足關(guān)系 eq() 的數(shù)據(jù)元素的位序,若這樣的元素不存在,則返回值為 0
  bool PriorElem(T e, bool(*eq) (T, T), T &pre_e)const;
  //若 e 與表的某數(shù)據(jù)元素滿足定義的 eq() 相等關(guān)系,且該數(shù)據(jù)不是表中第一個(gè),
  //則用 pre_e 返回它的前驅(qū),否則操作失敗,pre_e 無(wú)定義
  bool NextElem(T e, bool(*eq) (T, T), T &next_e)const;
  //若 e 與表中的某數(shù)據(jù)元素滿足定義的 eq() 相等關(guān)系,且該數(shù)據(jù)不是表中最后一個(gè),
  //則用 next_e 返回它的后繼,否則操作失敗,next_e 無(wú)定義
  bool ListDelete(int i, T &e);
  //刪除線性表第 i 個(gè)數(shù)據(jù)元素(1 <= i <= ListLength()),并用 e 返回其值
  void ListTraverse(void(*visit) (T*))const;
  //依次對(duì)每個(gè)數(shù)據(jù)元素調(diào)用函數(shù) visit()
  virtual bool GetElem(int i, T &e)const=0;  //純虛函數(shù)
  //用 e 返回線性表第 i 個(gè)元素的值(1 <= i <= ListLength())
  virtual bool ListInsert(int i, T e)=0;
  //在線性表第 i 個(gè)位置(1 <= i <= ListLength())之前插入新的數(shù)據(jù)元素
  virtual int ListLength()const=0;  //返回線性表的長(zhǎng)度,常成員函數(shù),不改變對(duì)象的值
};

1. 順序存儲(chǔ)結(jié)構(gòu)

順序存儲(chǔ)結(jié)構(gòu)容易實(shí)現(xiàn)隨機(jī)查找線性表的第 i 個(gè)元素的操作,但在實(shí)現(xiàn)插入和刪除操作時(shí)要移動(dòng)大量的數(shù)據(jù)元素。所以,它適用于數(shù)據(jù)相對(duì)穩(wěn)定的線性表。

實(shí)現(xiàn)

//繼承 AList 的順序表類
template<typename T>class SqList: public AList<T>
{
  friend void MergeList(const SqList<T>&, const SqList<T>&, SqList<T>&);
  //聲明普通函數(shù) MerfeList() 為 SqList 類的友元
private:
  T *elem;  //線性表存儲(chǔ)空間的基址
  int length;  //線性表的當(dāng)前表長(zhǎng)
  int listsize;  //線性表當(dāng)前的存儲(chǔ)容量
public:
  SqList(int k=1)
  {//構(gòu)造函數(shù),動(dòng)態(tài)生成具有 k 個(gè)初始存儲(chǔ)空間的空線性表
    elem = new T[k];
    assert(elem != NULL);  //存儲(chǔ)分配失敗,退出
    length = 0;  //空表長(zhǎng)度為 0
    listsize = k;  //初始存儲(chǔ)容量
  }
  ~SqList()
  {//析構(gòu)函數(shù)
    delete[] elem;  //釋放 elem 所指的存儲(chǔ)空間數(shù)組
  }
  void ClearList()
  {//重置線性表為空表
    length = 0;
  }
  bool ListEmpty()const  //常成員函數(shù),不會(huì)改變對(duì)象的值
  {//若線性表為空表,則返回 true;否則返回 false
    return length == 0;
  }
  int ListLength()const
  {//返回線性表的長(zhǎng)度
    return length;
  }
  bool GetElem(int i, T &e)const
  {//用 e 返回線性表第 i 個(gè)元素的值(1 <= i <= ListLength())
    if (i < 1 || i > length)  //i 不再表的范圍之內(nèi)
      return false;
    e = *(elem + i - 1);  //將第 i 個(gè)元素的值賦給 e
    return true;
  }
  int LocateElem(T e, bool(*eq) (T, T))const
  {//返回第一個(gè)與 e 滿足關(guān)系 eq() 的數(shù)據(jù)元素的位序,若這樣的元素不存在,則返回值為 0
    int i = 1;  //i 的初值指第一個(gè)元素
    while(i <= length && !eq(*(elem + i - 1), e))
    //i 沒超出表的范圍且 i 指向的數(shù)據(jù)元素與 e 不滿足關(guān)系
      i++;  //計(jì)數(shù)加 1 ,繼續(xù)往后找
    if (i <= length)  //找到滿足關(guān)系的數(shù)據(jù)元素
      return i;  //返回其位序
    else  //沒找到滿足關(guān)系的數(shù)據(jù)元素
      return 0;
  }
  int PriorElem(T e, bool(*eq) (T, T), T &pre_e)const
  {//若 e 與表的某數(shù)據(jù)元素滿足 eq() 關(guān)系,且該數(shù)據(jù)元素不是表中第一個(gè),
   //則用 pre_e 返回它的前驅(qū),否則操作失敗,pre_e 無(wú)定義
    int i = LocateElem(e, eq);  //將第一個(gè)滿足關(guān)系的數(shù)據(jù)元素的位序賦給 i
    if (i <= 1)  //沒找到,或是第一個(gè)元素
      return false;  //操作失敗
    else  //找到了值為 e 的元素,其位序?yàn)?i
    {
      pre_e = *(elem + i - 2);  //將前一個(gè)元素的值賦給 pre_e
      return true;  //操作成功
    }
  }
  bool NextElem(T e, bool(*eq) (T, T), T &next_e)const
  {//若 e 與表的某數(shù)據(jù)元素滿足 eq() 關(guān)系,且該數(shù)據(jù)元素不是表中最后一個(gè),
   //則用 next_e 返回它的后繼,否則操作失敗,next_e 無(wú)定義
    int i = LocateElem(e, eq);
    if (i == 0 || i == length)  //沒找到,或是最后一個(gè)元素
      return false;  
    else
    {
      next_e = *(elem + i);
      return true;
    }
  }
  bool ListInsert(int i, T e)
  {//在線性表第 i 個(gè)位置(1 <= i <= ListLength())之前插入新的數(shù)據(jù)元素 e
    T *newbase, *q, *p;
    if (i < 1 || i > length)  //i 值不合法
      return false;
    if (length == listsize)  //當(dāng)前存儲(chǔ)空間已滿
    {
      newbase = new T[listsize * 2];
      assert(newbase != NULL);  //存儲(chǔ)空間分配失敗,退出
      for (int j = 0; j < length; j++)
        *(newbase + j) = *(elem + j);  //將原表空間中的數(shù)據(jù)復(fù)制到新的表空間
      delete[] elem;  //釋放原表空間
      elem = newbase;  //新基址賦給 elem
      listsize *= 2;  //更新存儲(chǔ)容量
    }
    q = elem + i - 1;  // q 為插入位置
    for (p = elem + length - 1; p >= q; p--)  //插入位置之后的元素后移
      *(p + 1) = *p;
    *q = e;
    length++;
    return true;
  }
  bool ListDelete(int i, T &e)
  {//刪除線性表第 i 個(gè)元素(1 <= i <= ListLength()),并用 e 返回其值
    T *p, *q;
    if (i < 1 || i > length)  //i 值不合法
      return false;
    p = elem + i - 1;  //p 為被刪除元素的位置
    e = *p;
    q = elem + length -1;  //q 為表尾元素的位置
    for (++p; p <= q; ++p)  //被刪除元素之后的元素前移
      *(p - 1) = *p;
    length--;
    return true;
  }
  void ListTraverse(void(*visit) (T*))const;  
  {//依次對(duì)每個(gè)數(shù)據(jù)元素調(diào)用函數(shù) visit()
    for (int i = 0; i < length; i++)
      visit(elem + i);  //對(duì)每個(gè)數(shù)據(jù)元素調(diào)用 visit()
    cout << endl;
  }
};

2. 鏈?zhǔn)酱鎯?chǔ)

與順序存儲(chǔ)相比,鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)在實(shí)現(xiàn)插入、刪除的操作時(shí)不需要移動(dòng)大量數(shù)據(jù)元素,但是不容易實(shí)現(xiàn)隨機(jī)存取線性表的第 i 個(gè)數(shù)據(jù)元素的操作。所以,鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)適用于經(jīng)常需要進(jìn)行插入和刪除操作的線性表。

2.1 單鏈表

實(shí)現(xiàn)

//單鏈表結(jié)點(diǎn)類型結(jié)構(gòu)體
template<typename T>struct LNode
{
  T data;  //結(jié)點(diǎn)數(shù)據(jù)類型
  LNode<T> *next;  //后繼指針
};

//單鏈表的類
template<typename T>class LinkList: public AList
{//帶模板并繼承 AList 的單鏈表類
  friend void MergeList(LinkList<T>&, LinkList<T>&);
protected:
  LNode<T> *Head;  //頭指針
public:
  LinkList()
  {//構(gòu)造函數(shù),構(gòu)造一個(gè)空的線性表
    Head = new LNode<T>;  //產(chǎn)生頭結(jié)點(diǎn)
    assert(Head != NULL);  //存儲(chǔ)空間分配失敗,退出
    Head->next = NULL;  //頭結(jié)點(diǎn)的指針為空
  }
  ~LinkList()
  {//析構(gòu)函數(shù),銷毀線性表
    ClearList();  //置為空表
    delete Head;  //釋放頭結(jié)點(diǎn)
  }
  void ClearList()const
  {//重置線性表為空
    LNode<T> *q, *p = Head->next;  //p 指向第一個(gè)結(jié)點(diǎn)
    Head->next = NULL;  //頭結(jié)點(diǎn)指針域?yàn)榭?    while(!p = NULL)  //釋放其他結(jié)點(diǎn)
    {
      q = p->next;
      delete p;
      p = q;
    }
  }
  bool ListEmpty()const
  {//若線性表為空表,則返回 true,否則返回 false
    return Head->next == NULL;
  }
  int ListLength()const
  {//返回線性表的長(zhǎng)度
    int i = 0;  //計(jì)數(shù)器初值為 0
    LNode<T> *p = Head->next;  //p 指向第一個(gè)結(jié)點(diǎn)
    while(p != NULL)  //沒到表尾
    {
      i++;
      p->next;
    }
    return i;
  }
  bool GetElem(int i, T &e)const
  {//當(dāng)?shù)?i 個(gè)元素存在(1 <= i <= ListLength())時(shí),其值賦給 e 并返回 true ,
   //否則返回 false
    int j = 1;
    LNode<T> *p = Head->next;  //p 指向第一個(gè)結(jié)點(diǎn)
    while(p != NULL && j < i)  //順序查找
    {
      j++;
      p = p->next;
    }
    if (p == NULL || j > i)
      return false;
    e = p->data;
    return true;
  }
  int LocateElem(T e, bool(*eq) (T, T))const
  {//返回第一個(gè)與 e 滿足 eq() 關(guān)系的數(shù)據(jù)元素的位序,若這樣的元素不存在,則返回 0
    int i = 0;
    LNode<T> *p = Head->next;
    while(p != NULL)
    {
      i++;
      if (eq(p->data, e))
        return i;
      p = p->next;
    }
    return 0;
  }
  bool PriorElem(T e, bool(*eq) (T, T), T &pre_e)const
  {//若 e 與表中的某數(shù)據(jù)元素滿足 eq() 關(guān)系,且該元素不是表中第一個(gè),
   //則用 pre_e 返回它的前驅(qū),否則操作失敗,pre_e 無(wú)定義
    LNode<T> *p = Head->next;
    while(p != NULL && p->next != NULL)  //p 所指結(jié)點(diǎn)有后繼
    {
      q = p->next;
      if (eq(q->data, e))
      {
        pre_e = p->data;
        return true;
      }
      p = q;  //p 的后繼 q 不等于 e ,p 向后移
    }
    return false;
  }
  bool NextElem(T e, bool(*eq) (T, T), T &next_e)const
  {//若 e 與表中某數(shù)據(jù)元素滿足 eq() 關(guān)系,且該元素不是表中最后一個(gè),
   //則用 next_e 返回它的后繼,否則操作失敗,next_e 無(wú)定義
    LNode<T> *p = Head->next;
    while(p != NULL && p->next != NULL)
    {
      if (eq(p->data, e))
      {
        next_e = p->next->data;
        return true;
      }
      p = p->next;
    }
    return false;
  }
  bool ListInsert(int i, T e)
  {//在帶頭結(jié)點(diǎn)的單鏈表中第 i 個(gè)位置(1 <= i <= ListLength())之前插入新的數(shù)據(jù)元素 e
    int j = 0;
    LNode<T> *s, *p = Head;
    while(p != NULL && j < i-1)  //尋找第 i-1 個(gè)結(jié)點(diǎn)
    {
      j++;
      p = p->next;
    }
    if (p == NULL || j > i-1)  //i 小于 1 或者大于表長(zhǎng)+1
      return false;
    s = new LNode<T>;  //生成新結(jié)點(diǎn)
    if (s == NULL)  //生成新結(jié)點(diǎn)失敗
      return false;  //插入失敗
    s->data = e;
    s->next = p->next;  //新結(jié)點(diǎn)指向原第 i 個(gè)結(jié)點(diǎn)
    p-next = s;  //原第 i-1 個(gè)結(jié)點(diǎn)指向新結(jié)點(diǎn)
    return true;  //插入成功
  }
  bool ListDelete(int i, T &e)const
  {//在帶頭結(jié)點(diǎn)的單鏈線性表中刪除第 i 個(gè)數(shù)據(jù)元素(1 <= i <= ListLength()),
   //并用 e 返回其值
    int j = 0;
    LNode<T> *q, *p = Head;
    while(p->next != NULL && j < i-1)  //尋找第 i 個(gè)結(jié)點(diǎn),并令 p 指向其前驅(qū)
    {
      j++;
      p = p->next;
    }
    if (p->next == NULL || j > i-1)  
      return false;
    q = p->next;  //q 指向刪除結(jié)點(diǎn)
    p->next = q->next;  //待刪結(jié)點(diǎn)的前驅(qū)指向待刪結(jié)點(diǎn)的后繼
    e = q->data;
    delete q;
    return true;
  }
  void ListTraverse(void(*visit) (T*))const
  {//依次對(duì)每個(gè)數(shù)據(jù)元素調(diào)用函數(shù) visit()
    LNode<T> *p = Head->next;
    while(p != NULL)
    {
      visit(&p->data);
      p = p->next;
    }
    cout << endl;
  }
};

2.2 單循環(huán)鏈表

單循環(huán)鏈表結(jié)點(diǎn)的存儲(chǔ)結(jié)構(gòu)和單鏈表結(jié)點(diǎn)的一樣,不同的是:?jiǎn)窝h(huán)鏈表最后一個(gè)結(jié)點(diǎn)的指針域指向頭結(jié)點(diǎn),而不是 NULL 。這樣,由表尾很容易找到表頭。但若鏈表較長(zhǎng),則由表頭找到表尾仍較費(fèi)時(shí)。因而,單循環(huán)鏈表往往設(shè)立尾指針而不是頭指針。這樣,查找最后一個(gè)結(jié)點(diǎn)和頭結(jié)點(diǎn)都很方便。這在兩個(gè)鏈表首尾相連合并成一個(gè)鏈表時(shí)尤為方便。

實(shí)現(xiàn)

//設(shè)立尾指針的單循環(huán)鏈表的類
template<typename T>class LinkListCy: public AList
{//帶模板并繼承 AList 的單循環(huán)鏈表類
  friend void MergeList(LinkListCy<T>&, LinkListCy<T>&);
private:
  LNode<T> *Tail;  //尾指針
public:
  LinkListCy()
  {//構(gòu)造函數(shù),構(gòu)造一個(gè)空的線性表
    Tail = new LNode<T>;  //產(chǎn)生頭結(jié)點(diǎn),并使 Tail 指向此頭結(jié)點(diǎn)(尾指針指向頭結(jié)點(diǎn))
    assert(Tail != NULL);  //存儲(chǔ)分配失敗,退出
    Tail->next = Tail;  //頭結(jié)點(diǎn)的指針域指向頭結(jié)點(diǎn)
  }
  ~LinkListCy()
  {//析構(gòu)函數(shù),銷毀線性表
    ClearList();  //將線性表重置為空表
    delete Tail;  //釋放頭結(jié)點(diǎn)
  }
  void ClearList()
  {//將線性表重置為空表
    LNode<T> *p, *q;
    Tail = Tail->next;  //Tail 指向頭結(jié)點(diǎn)
    p = Tail->next;  //p 指向第一個(gè)結(jié)點(diǎn)
    while(p != Tail)  //沒到表尾
    {
      q = p->next;
      delete p;
      p = q;
    }
    Tail->next = Tail;  //頭結(jié)點(diǎn)指針域指向自身
  }
  bool ListEmpty()const
  {//若線性表為空表,則返回 true ;否則返回 false
    return Tail->next==Tail;  
  }
  int ListLength()const
  {//返回線性表中數(shù)據(jù)元素個(gè)數(shù)
    int i = 0;
    LNode<T> *p = Tail->next;  //p指向頭結(jié)點(diǎn)
    while(p != Tail)
    {
      i++;
      p = p->next;
    }
    return i;
  }
  bool GetElem(int i, T &e)const
  {//在第 i 個(gè)元素存在時(shí),其值賦給 e 并返回 true ;否則返回 false
    int j = 1;
    LNode<T> *p = Tail->next->next;  //p 指向第一個(gè)結(jié)點(diǎn)
    if (i <= 0 || i > ListLength())
      return false;
    while(j < i)
    {
      j++;
      p = p->next;
    }
    e = p->data;
    return true;
  }
  int LocateElem(T e, bool(*eq) (T, T))const
  {//返回第一個(gè)與 e 滿足 eq() 關(guān)系的數(shù)據(jù)元素的位序,若這樣的元素不存在,則返回 0
    int i = 0;
    LNode<T> *p = Tail->next->next;  //p 指向第一個(gè)結(jié)點(diǎn)
    while(p != Tail->next)
    {
      i++;
      if (eq(p->data, e))
        return i;
      p = p->next;
    }
    return 0;
  }
  bool PriorElem(T e, bool(*eq) (T, T), T &pre_e)const
  {//若 e 與表中的某數(shù)據(jù)元素滿足 eq() 關(guān)系,且該元素不是表中第一個(gè),
   //則用 pre_e 返回它的前驅(qū),否則操作失敗,pre_e 無(wú)定義
    LNode<T> *q, *p = Tail->next->next;  //p 指向第一個(gè)結(jié)點(diǎn)
    q = p->next;
    while(q != Tail->next)  
    {
      if (eq(q->data, e))
      {
        pre_e = p->data;
        return true;
      }
      p = q;  //p 的后繼 q 不等于 e ,p 向后移
      q = q->next;
    }
    return false;
  }
  bool NextElem(T e, bool(*eq) (T, T), T &next_e)const
  {//若 e 與表中某數(shù)據(jù)元素滿足 eq() 關(guān)系,且該元素不是表中最后一個(gè),
   //則用 next_e 返回它的后繼,否則操作失敗,next_e 無(wú)定義
    LNode<T> *p = Tail->next->next;
    while(p != Tail)
    {
      if (eq(p->data, e))
      {
        next_e = p->next->data;
        return true;
      }
      p = p->next;
    }
    return false;
  }
  bool ListInsert(int i, T e)
  {//在帶頭結(jié)點(diǎn)的單鏈表中第 i 個(gè)位置(1 <= i <= ListLength())之前插入新的數(shù)據(jù)元素 e
    int j = 0;
    LNode<T> *p = Head;
    if (i <= 0 || i > ListLength()+1)
      return false;
    while(j < i-1)  //尋找第 i-1 個(gè)結(jié)點(diǎn)
    {
      j++;
      p = p->next;
    }
    s = new LNode<T>;  //生成新結(jié)點(diǎn)
    if (s == NULL)  //生成新結(jié)點(diǎn)失敗
      return false;  //插入失敗
    s->data = e;
    s->next = p->next;  //新結(jié)點(diǎn)指向原第 i 個(gè)結(jié)點(diǎn)
    p-next = s;  //原第 i-1 個(gè)結(jié)點(diǎn)指向新結(jié)點(diǎn)
    if (p == Tail)  //插在表尾
      Tail = s;
    return true;  //插入成功
  }
  bool ListDelete(int i, T &e)
  {//在帶頭結(jié)點(diǎn)的單鏈線性表中刪除第 i 個(gè)數(shù)據(jù)元素(1 <= i <= ListLength()),
   //并用 e 返回其值
    int j = 0;
    LNode<T> *q, *p = Tail->next;
    if (i <= 0 || i > ListLength())
      return false;
    while(j < i-1)  //尋找第 i 個(gè)結(jié)點(diǎn),并令 p 指向其前驅(qū)
    {
      j++;
      p = p->next;
    }
    q = p->next;  //q 指向刪除結(jié)點(diǎn)
    p->next = q->next;  //待刪結(jié)點(diǎn)的前驅(qū)指向待刪結(jié)點(diǎn)的后繼
    e = q->data;
    if (Tail == q)
      Tail=p;
    delete q;
    return true;
  }
  void ListTraverse(void(*visit) (T*))const
  {//依次對(duì)每個(gè)數(shù)據(jù)元素調(diào)用函數(shù) visit()
    LNode<T> *p = Tail->next->next;
    while(p != Tail->next)  //p 不指向頭結(jié)點(diǎn)
    {
      visit(&p->data);
      p = p->next;
    }
    cout << endl;
  }
};

2.3 雙向循環(huán)鏈表

實(shí)現(xiàn)

//雙向結(jié)點(diǎn)類型結(jié)構(gòu)體
template<typename T>struct DLNode
{
  T data;
  DLNode<T> *prior, *next;
}

//雙向鏈表類
template<typename T> class DLinkList: public AList<T>
{//帶模板并繼承 AList 的雙向鏈表類
private:
  DLNode<T> *Head;  //頭指針
  DLNode<T>* GetElemP(int i)const
  {//在雙向鏈表中返回第 i 個(gè)結(jié)點(diǎn)的地址,i 為 0 ,則返回頭結(jié)點(diǎn)的地址
   //若第 i 個(gè)結(jié)點(diǎn)不存在,則返回 NULL
    int j = 0;
    DLNode<T> *p = Head;
    if (i < 0)
      return NULL;
    if (i == 0)
      return p;
    do
    {
      p = p->next;
      j++;
    }while(p != Head && j < i);  //p 沒返回到頭結(jié)點(diǎn)并且還沒到第 i 個(gè)結(jié)點(diǎn)
    if (p == Head)  //查找失敗
      return NULL;
    else
      return p;
  }
  DLNode<T>* GetElemE(T e, bool(*eq) (T, T))const
  {//在雙向鏈表中返回第一個(gè)與 e 滿足定義的 eq() 相等關(guān)系的數(shù)據(jù)元素地址
   //若這樣的數(shù)據(jù)元素不存在,返回 NULL
    DLNode<T> *P = Head->next;
    while(p != Head && !eq(p->data, e))
      p = p->next;
      if (p == Head)  //這樣的元素不存在
        return NULL;
      else
      return p;
  }
public:
  DLinkList()
  {//構(gòu)造一個(gè)空的雙向循環(huán)鏈表
    Head = new DLNode<T>;  //產(chǎn)生頭結(jié)點(diǎn)
    assert(Head != NULL)
    Head->next = Head->prior = Head;  //頭結(jié)點(diǎn)的指針域指向自身
  }  
  ~DLinkList()
  {//析構(gòu)函數(shù),銷毀雙向鏈表
    ClearList();  //置為空表
    delete Head;  //釋放頭結(jié)點(diǎn)
  }
  void ClearList()const
  {//重置雙向循環(huán)線性表為空表
    DLNode<T> *P = Head->next;
    while(p != Head)
    {
      p = p->next;
      delete p->prior;
    }
    Head->next = Head->prior = Head;
  }
  bool ListEmpty()const
  {//若線性表為空表,則返回 true ;否則返回 false
    return Head->next == Head;
  }
  int ListLength()const
  {//返回線性表的長(zhǎng)度
    int i = 0;
    DLNode<T> *p = Head->next;
    while(p != Head)
    {
      i++;
      p = p->next;
    }
    return i;
  }
  bool GetElem(int i, T &e)const
  {//在第 i 個(gè)元素存在時(shí),其值賦給 e 并返回 true ;否則返回 false
    DLNode<T> *p = GetElemP(i);  //p 指向第 i 個(gè)結(jié)點(diǎn)
    if (p != NULL)  //第 i 個(gè)結(jié)點(diǎn)存在
    {
      e = p->data;
      return true;
    }
    else
      return false;
  }
  int LocateElem(T e, bool(*eq) (T, T))const
  {//返回第一個(gè)與 e 滿足 eq() 關(guān)系的數(shù)據(jù)元素的位序,若這樣的元素不存在,則返回 0
    int i = 0;
    LNode<T> *p = Head->next;  //p 指向第一個(gè)結(jié)點(diǎn)
    while(p != Head)
    {
      i++;
      if (eq(p->data, e))
        return i;
      p = p->next;
    }
    return 0;
  }
  bool PriorElem(T e, bool(*eq) (T, T), T &pre_e)const
  {//若 e 與表中的某數(shù)據(jù)元素滿足 eq() 關(guān)系,且該元素不是表中第一個(gè),
   //則用 pre_e 返回它的前驅(qū),否則操作失敗,pre_e 無(wú)定義
    LNode<T> *p = GetElemE(e, eq);  //p 指向結(jié)點(diǎn) e
    if (p != NULL && p->prior != Head)  //p 指向值為 e 的結(jié)點(diǎn)且該結(jié)點(diǎn)不是第一個(gè)結(jié)點(diǎn)
    {
      pre_e = p->prior->data;
      return true;
    }
    return false;
  }
  bool NextElem(T e, bool(*eq) (T, T), T &next_e)const
  {//若 e 與表中某數(shù)據(jù)元素滿足 eq() 關(guān)系,且該元素不是表中最后一個(gè),
   //則用 next_e 返回它的后繼,否則操作失敗,next_e 無(wú)定義
    DLNode<T> *p = GetElemE(e, eq);  //p 指向結(jié)點(diǎn) e
    if (p != NULL && p->next != Head)  //p 指向值為e的結(jié)點(diǎn)且該結(jié)點(diǎn)不是最后一個(gè)結(jié)點(diǎn)
    {
      pre_e = p->next->data;
      return true;
    }
    return false;
  }
  bool ListInsert(int i, T e)
  {//在帶頭結(jié)點(diǎn)的單鏈表中第 i 個(gè)位置(1 <= i <= ListLength())之前插入新的數(shù)據(jù)元素 e
    DLNode<T> *s, *p = GetElemP(i-1);  //確定第 i 個(gè)結(jié)點(diǎn)前驅(qū)的位置指針 p
    if (p = NULL) //第 i 個(gè)結(jié)點(diǎn)的前驅(qū)不存在(設(shè)頭結(jié)點(diǎn)為第 0 個(gè)結(jié)點(diǎn))
      return false;
    s = new DLNode<T>;  //生成新結(jié)點(diǎn)
    if (s == NULL)
      return false;  //生成失敗
    s->data = e;
    s->prior = p;
    s->next = p->next;
    p->next->prior = s;
    p->next = s;
    return true;
  }
  bool ListDelete(int i, T &e)
  {//在帶頭結(jié)點(diǎn)的單鏈線性表中刪除第 i 個(gè)數(shù)據(jù)元素(1 <= i <= ListLength()),
   //并用 e 返回其值
    DLNode<T> *p =GetElemP(i);
    if (p == NULL)
      return false;
      e = p->data;
      p->prior->next = p->next;
      p->next->prior = p->prior;
      delete p;
      return true;
  }
  void ListTraverse(void(*visit) (T*))const
  {//依次對(duì)每個(gè)數(shù)據(jù)元素調(diào)用函數(shù) visit()
    DLNode<T> *p = Head->next;
    while(p != Head)  //p 不指向頭結(jié)點(diǎn)
    {
      visit(&p->data);
      p = p->next;
    }
    cout << endl;
  }
  void ListBackTraverse(void(*visit) (T*))const
  {//由雙向循環(huán)線性表的頭結(jié)點(diǎn)出發(fā),逆序?qū)γ總€(gè)元素調(diào)用函數(shù) visit()
    DLNode<T> *p = Head->prior;  //p 指向尾結(jié)點(diǎn)
    while(p != Head)
    {
      visit(&p->data);
      p = p->prior;
    }
    cout << endl;
  }
};

2.4 不設(shè)頭結(jié)點(diǎn)的鏈表

鏈表也可以不設(shè)頭結(jié)點(diǎn),這樣看起來(lái)更自然一些。但不設(shè)頭結(jié)點(diǎn)會(huì)使得對(duì)第 1 個(gè)元素做插入或刪除的操作與其他元素不同,這會(huì)帶來(lái)編程上的麻煩。不設(shè)頭結(jié)點(diǎn)的雙向循環(huán)鏈表在動(dòng)態(tài)存儲(chǔ)管理中有應(yīng)用。下面對(duì)它們做簡(jiǎn)單介紹,因?yàn)槭呛?jiǎn)單介紹,沒有完全實(shí)現(xiàn)線性表抽象類 AList 的 3 個(gè)純虛函數(shù),故他們不能繼承 AList 。

實(shí)現(xiàn)

//不設(shè)頭結(jié)點(diǎn)的單鏈表類
template<typename T>class LinkListNH
{//帶模板的不設(shè)頭結(jié)點(diǎn)的單鏈表類
private:
  LNode<T> *Head;  //頭指針
public:
  LinkListNH()
  {//構(gòu)造函數(shù),構(gòu)造一個(gè)空的線性表
    Head = NULL;  //指針為空
  }
  ~LinkListNH()
  {//析構(gòu)函數(shù),銷毀線性表
    ClearList();  //將線性表重置為空表
  }
  void ClearList()
  {//將線性表重置為空表
    LNode<T> *p;
    while(Head != NULL)  //表不為空
    {
      p = Head;  //p 指向第一個(gè)結(jié)點(diǎn)
      Head = Head->next;  //Head 指向下一個(gè)結(jié)點(diǎn)
      delete p;
    }
  }
  int ListLength()const
  {//返回線性表的長(zhǎng)度
    int i = 0;
    LNode<T> *p = Head;  //p指向頭結(jié)點(diǎn)
    while(p != NULL)
    {
      i++;
      p = p->next;
    }
    return i;
  }
  int LocateElem(T e, bool(*eq) (T, T))const
  {//返回第一個(gè)與 e 滿足 eq() 關(guān)系的數(shù)據(jù)元素的位序,若這樣的元素不存在,則返回 0
    int i = 0;
    LNode<T> *p = Head;  //p 指向第一個(gè)結(jié)點(diǎn)
    while(p != NULL)
    {
      i++;
      if (eq(p->data, e))
        return i;
      p = p->next;
    }
    return 0;
  }
  LNode<T>* Point(T e, bool(*eq) (T, T), LNode<T>* &p)const
  {//查找表中第一個(gè)與 e 滿足 eq() 關(guān)系的結(jié)點(diǎn),如找到,返回指向該結(jié)點(diǎn)的指針,
   //p 指向該結(jié)點(diǎn)的前驅(qū)(若該結(jié)點(diǎn)是第一個(gè)結(jié)點(diǎn),則 p=NULL),沒找到則返回NULL,p無(wú)定義
    if (Head)  //表不空
      if (eq(Head->data, e))
      {
        p = NULL;
        return Head;
      }
      else
      {
        p = Head;  
        while(p->next->data, e)
          if (eq(p->next->data, e))
            return p->next;
          else
            p = p->next;
      }
    return NULL;
  }
  bool ListInsert(int i, T e)
  {//在不設(shè)頭結(jié)點(diǎn)的單鏈線性表第 i 個(gè)位置之前插入元素 e
    int j = 1;
    LNode<T> *s, *p = Head;
    if (i < 1)
      return false;
    s = new LNode<T>;
    if (s == NULL)
      return false;
    s->data = e;
    if (i == 1)  //插在表頭
    {
      s->next = Head;  //新結(jié)點(diǎn)指向原第一結(jié)點(diǎn)
      Head = s;  //Head 指向新結(jié)點(diǎn)
    }
    else
    {//插在表的其余處
      while(p != NULL && j < i-1)  //尋找第 i-1 個(gè)結(jié)點(diǎn)
      {
        j++;
        p = p->next;
      }
      if (p == NULL)  //i 大于表長(zhǎng)+1
        return false;
      else  //p 指向第 i-1 個(gè)結(jié)點(diǎn)
      {
        s->next = p->next;
        p-next = s;
      }
    }
    return true;
  }
  bool ListDelete(T e, bool(*eq) (T, T))
  {//在不設(shè)頭結(jié)點(diǎn)的單鏈線性表中,刪除與 e 滿足 eq() 關(guān)系的結(jié)點(diǎn)
    LNode<T> *p, *q;
    q = Point(e, eq, p);  //p 指向待刪結(jié)點(diǎn)的前驅(qū)
    if (q == NULL)  //沒找到待刪結(jié)點(diǎn)
      return false;
    else  //找到待刪結(jié)點(diǎn)
    {
      if (p == NULL)  //待刪結(jié)點(diǎn)是第一個(gè)結(jié)點(diǎn)
        Head = q->next;
      else
        p->next = q->next;
      delete q;
      return true;
    }
  }
  void ListTraverse(void(*visit) (T*))const
  {//依次對(duì)每個(gè)數(shù)據(jù)元素調(diào)用函數(shù) visit()
    LNode<T> *p = Head;  //p 指向第一個(gè)結(jié)點(diǎn)
    while(p != NULL)  //p 所指結(jié)點(diǎn)存在
    {
      visit(&p->data);
      p = p->next;
    }
    cout << endl;
  }
};
//不設(shè)頭結(jié)點(diǎn)的雙向鏈表的類
template<typename T>class DLinkListNH
{//帶模板的不設(shè)頭結(jié)點(diǎn)的雙向鏈表類
  friend void Joseph(int, int);
  friend class BoundaryLogo;  //聲明邊界標(biāo)識(shí)法類為友類
  friend class BuddySystem;  //聲明伙伴系統(tǒng)為友類
private:
  DLNode<T> *Head;  //頭指針
  DLNode<T>* GetElemP(int i)const
  {//在雙向鏈表中返回第 i 個(gè)結(jié)點(diǎn)的地址,若第 i 個(gè)結(jié)點(diǎn)不存在,返回 NULL
    int j = 1;
    DLNode<T> *p = Head;  //p 指向第一個(gè)結(jié)點(diǎn)
    if (i <= 0 || Head == NULL)
      return NULL;
    if (i == 1)  //第一個(gè)結(jié)點(diǎn)
      return p;
    do
    {
      p = p->next;
      j++;
    }while(p != Head && j < i);
    if (p == Head)  //第 i 個(gè)結(jié)點(diǎn)不存在
      return NULL;
    else
      return p;
  }
public:
  DLinkListNH()
  {//構(gòu)造一個(gè)空的雙向循環(huán)鏈表
    Head = NULL;  //頭指針為空
  }
  ~DLinkListNH()
  {//析構(gòu)函數(shù),銷毀雙向循環(huán)鏈表
    ClearList();
  }
  void ClearList()
  {//重置雙向循環(huán)鏈表為空表
   //不帶頭結(jié)點(diǎn)的循環(huán)鏈表可以解開先循環(huán)再依次刪除,
   //也可以不解開循環(huán)進(jìn)行依次刪除,不過(guò)最后還得單獨(dú)把頭指針?biāo)赶虻慕Y(jié)點(diǎn)刪除
    DLNode<T> *p = Head;  //p 指向第一個(gè)結(jié)點(diǎn)
    if (Head != NULL)
    {
      Head->prior->next = NULL;  //打開循環(huán)鏈表為單鏈表,很關(guān)鍵
      while(p != NULL)
      {
        p = p->next;
        delete Head;
        Head = p;
      }
    }
  }
  int ListLength()const
  {//返回線性表的長(zhǎng)度
    int i = 0;
    DLNode<T> *p = Head;
    if (Head != NULL)
      do
      {
        i++;
        p = p->next;
      }while(p != Head);
    return i;
  }
  bool ListInsert(int i, T e)
  {//在不設(shè)頭結(jié)點(diǎn)的雙向循環(huán)鏈表中第 i 個(gè)位置之前插入新的數(shù)據(jù)元素 e
    DLNode<T> *s, *p = GetElemP(i-1);  //p 指向第 i-1 個(gè)結(jié)點(diǎn)
    s = new DLNode<T>;
    if (s == NULL)
      return false;
    s->data = e;
    if (i == 1)  //在第一個(gè)結(jié)點(diǎn)前插入
    {
      if (Head == NULL)
        s->prior = s->next =s;
      else
      {
        s->prior = Head->prior;
        s->next = Head;
        s->prior->next = s;
        s->next->prior =s;
      }
      Head = s;
      return true;
    }
    else  //i > 1
    {
      if (p == NULL)  //第 i-1 個(gè)結(jié)點(diǎn)不存在
        return false;
      else
      {
        s->next = p->next;
        s->prior = p;
        s->next->prior = s;
        p->next = s;
        return true;
      }
    }
  }
  bool ListDelete(int i, T &e)
  {//刪除不帶頭結(jié)點(diǎn)的雙向循環(huán)鏈表的第 i 個(gè)元素,并用 e 返回其值
    DLNode<T> *p = GetElemP(i);  //p 指向第 i 個(gè)結(jié)點(diǎn)
    if (p == NULL)
      return false;
    e = p->data;
    if (p->next == p)  //表中只有一個(gè)元素,且將被刪除
      Head == NULL;
    else  //表中有多個(gè)元素
    {
      P->next->prior = p->prior;
      p->prior->next = p->next;
      if (p == Head)  //刪除的是第一個(gè)結(jié)點(diǎn)
        Head = p->next;
    }
    delete p;
    return true;
  }
  void ListTraverse(void(*visit) (T*))const
  {//依次對(duì)雙向循環(huán)鏈表的每個(gè)數(shù)據(jù)元素調(diào)用函數(shù) visit()
    DLNode<T> *p = Head;
    if (Head != NULL)
      do
      {
        visit(p->data);
        p = p->next;
      }while(p != Head)
    cout << endl;
  }
};

用不設(shè)頭結(jié)點(diǎn)的循環(huán)鏈表解決某些問(wèn)題比較方便,如約瑟夫環(huán)問(wèn)題:n 個(gè)小孩圍坐一圈,由第一個(gè)小孩開始,依次循環(huán)報(bào)數(shù),報(bào)到 m 的小孩出列。從下一個(gè)小孩重新開始循環(huán)報(bào)數(shù),直到所有小孩都出列,求小孩出列順序。

C++ 的標(biāo)準(zhǔn)模板庫(kù)(STL)也提供了鏈表類的操作,稱為 list (表),使用雙向鏈表實(shí)現(xiàn)的。可以訪問(wèn)cplusplus查詢相關(guān)操作函數(shù)。

3. 靜態(tài)鏈表存儲(chǔ)結(jié)構(gòu)

順序存儲(chǔ)結(jié)構(gòu)也可以實(shí)現(xiàn)鏈?zhǔn)酱鎯?chǔ)功能。首先,開辟一個(gè)充分大的結(jié)構(gòu)體數(shù)組。結(jié)構(gòu)體數(shù)組的一個(gè)成員(data)存放數(shù)據(jù),另一個(gè)成員(link)存放鏈表中的下一個(gè)數(shù)據(jù)元素在數(shù)組中的位置(下標(biāo)),這稱為靜態(tài)鏈表。

靜態(tài)鏈表存于數(shù)組中,單聊標(biāo)的輸出卻不是按數(shù)組的順序輸出的,是由一個(gè)指定的位置開始根據(jù) link 的值依次輸出的。靜態(tài)鏈表存儲(chǔ)結(jié)構(gòu)在赫夫曼樹和內(nèi)部排序中都有應(yīng)用。

實(shí)現(xiàn)

const int MAX_SIZE = 10;  //靜態(tài)鏈表的最大長(zhǎng)度
//靜態(tài)鏈表類
template<typename T>class StLinkList
{//帶模板的靜態(tài)鏈表類
  struct component  //類內(nèi)定義的結(jié)構(gòu)體,只用于本類內(nèi)
  {
    T data;
    int link;
  };
private:
  component SL[MAX_SIZE];  //靜態(tài)數(shù)組
  int NEW()
  {//若備用鏈表非空,則返回分配的結(jié)點(diǎn)下標(biāo)(備用鏈表的第一個(gè)結(jié)點(diǎn));否則返回 0
    int i = SL[MAX_SIZE - 1].link;  //備用鏈表第一個(gè)結(jié)點(diǎn)的位置
    if (i)  //備用鏈表非空
      SL[MAX_SIZE - 1].link = SL[i].link;  
      //備用鏈表的頭結(jié)點(diǎn)指向原備用鏈表的第二個(gè)結(jié)點(diǎn)
    return i;  //返回新開辟結(jié)點(diǎn)的下標(biāo)
  }
  void DELETE(int k)
  {//將下標(biāo)為 k 的空閑結(jié)點(diǎn)回收到備用鏈表中,成為備用鏈表的第一個(gè)結(jié)點(diǎn)
    SL[k].link = SL[MAX_SIZE - 1].link;  //回收結(jié)點(diǎn)的下標(biāo)指向備用鏈表的第一個(gè)結(jié)點(diǎn)
    SL[MAX_SIZE - 1].link = k;  //備用鏈表的頭結(jié)點(diǎn)指向新回收的結(jié)點(diǎn)
  }
public:
  StLinkList()
  {//構(gòu)造一個(gè)空的鏈表,表頭為單元 [0],其余單元鏈成一個(gè)備用鏈表
   //備用鏈表表頭為最后一個(gè)單元 [MAX_SIZE - 1],link 域 0 表示空指針
    int i;
    SL[0].link = 0;  //[0] 為空鏈表的表頭
    SL[MAX_SIZE - 1].link = 1;  //[1] 為備用鏈表的第一個(gè)單元
    for(i = 1; i < MAX_SIZE - 2; i++)
    //將其余單元鏈成以 [MAX_SIZE - 1] 為表頭的備用鏈表
      SL[i].link = i + 1;
    SL[MAX_SIZE - 2].link = 0;
  }
  void ClearList()
  {//將靜態(tài)鏈表重置為空表
    int j, i = SL[MAX_SIZE - 1].link;  //i 指示備用鏈表第一個(gè)結(jié)點(diǎn)的位序
    while(i)  //未到備用鏈表表尾
    {
      j = i;
      i = SL[i].link;
    }
    SL[j].link = SL[0].link;  //鏈表的第一個(gè)結(jié)點(diǎn)接到備用鏈表的尾部
    Sl[0].link = 0;  //鏈表空
  }
  bool ListEmpty()const
  {//若是空表,返回 true;否則返回 false
    return SL[0].link == 0;
  }
  int ListLength()const
  {//返回表中數(shù)據(jù)元素個(gè)數(shù)
    int j = 0, i = SL[0].link;  //i 指向鏈表的第一個(gè)結(jié)點(diǎn)的位序
    while(i)
    {
      i = SL[i].link;
      j++;
    }
    return j;
  }
  bool PriorElem(T e, bool(*eq) (T, T), T &pre_e)const
  {//若 e 與表中某數(shù)據(jù)元素滿足定義的 eq() 關(guān)系,且該數(shù)據(jù)不是表中第一個(gè),
   //則用 pre_e 返回它的前驅(qū),否則操作失敗,pre_e 無(wú)定義
    int j, i = SL[0].link;
    do
    {
      j = i;
      i = SL[i].link;
    }while(i && !eq(Sl[i].data, e));  //i 所指元素存在且其值不是 e ,繼續(xù)循環(huán)
    if (i)  //找到該元素
    {
      pre_e = SL[i].data;
      return true;
    }
    return false;  //沒找到該元素,或其無(wú)前驅(qū)
  }
  bool NextElem(T e, bool(*eq) (T, T), T &next_e)const
  {//若 e 與表中某數(shù)據(jù)元素滿足定義的 eq() 關(guān)系,且該元素不是表中最后一個(gè),
   //則用 next_e 返回它的后繼,否則操作失敗,next_e 無(wú)定義
    int i = SL[0].link;
    while(i)
    {
      if (eq(SL[i].data, e) && SL[i].link)  //找到該元素且其有后繼
      {
        next_e = SL[SL[i].link].data;
        return true;
      }
      i = SL[i].link;
    }
    return false;  //不存在該元素,或者其無(wú)后繼
  }
  bool ListInsert(int i, T e)
  {//在靜態(tài)鏈表的第 i 個(gè)元素
    int m, k = 0;  //k 指示頭結(jié)點(diǎn)的位序
    for (m = 1; m < i; m++)
    {
      k = SL[k].link;  //k 指向下一結(jié)點(diǎn)
      if (k == 0)  //已到表尾
        break;
    }
    if (m < i)  //表中沒有第 i-1 個(gè)結(jié)點(diǎn)
      return false;
    else  //表中有第 i-1 個(gè)結(jié)點(diǎn),并由 k 指向
    {
      m = NEW();  //申請(qǐng)新單元
      if (m)  //申請(qǐng)成功
      {
        SL[m].data = e;
        SL[m].link = SL[k].link;
        SL[k].link = m;
        return true;
      }
      return false;
    }
  }
  bool ListDelete(int i, T &e)
  {//刪除第 i 個(gè)數(shù)據(jù)元素,并用 e 返回其值
    int m, k = 0;  //k 指示頭結(jié)點(diǎn)的位序
    for(m = 1; m < i; m++)
    {
      k = SL[k].link;
      if (k == 0)  //已到表尾
        break;
    }
    if (m < i || SL[k].link == 0)  //表中沒有第 i-1 個(gè)結(jié)點(diǎn)或者沒有第 i 個(gè)結(jié)點(diǎn)
      return false;
    else
    {
      m = SL[k].link;
      SL[k].link = SL[m].link;
      e = SL[m].data;
      DELETE(m);
      return true;
    }
  }
  void ListTraverse(void(*visit) (T*))
  {//依次對(duì)每個(gè)元素調(diào)用函數(shù) visit()
    int i = SL[0].link;
    while(i)
    {
      visit(&SL[i].data);
      i = SL[i].link;
    }
    cout << endl;
  }
};

靜態(tài)鏈表存儲(chǔ)于數(shù)組中,但其順序卻不是按數(shù)組下標(biāo)的順序,而是像鏈表一樣,由當(dāng)前結(jié)點(diǎn) link 域的值決定下一結(jié)點(diǎn)的位置,這是鏈表的特性;又由于用數(shù)組存儲(chǔ),故稱為靜態(tài)鏈表。我們只要知道第一個(gè)結(jié)點(diǎn)(頭結(jié)點(diǎn))的位置就可以依次找到靜態(tài)鏈表中的其他結(jié)點(diǎn)。我們將不再鏈表中的空閑結(jié)點(diǎn)也鏈接成一個(gè)靜態(tài)鏈表,成為 “備用鏈表” 。靜態(tài)鏈表數(shù)組 SL 中有一個(gè)鏈表頭結(jié)點(diǎn)在位置 [0],有一個(gè)備用鏈表頭結(jié)點(diǎn)在位置 [MAX_SIZE - 1] ,其余結(jié)點(diǎn)不再鏈表中就在備用鏈表中。

當(dāng)靜態(tài)鏈表需要新結(jié)點(diǎn)時(shí),我們把備用鏈表中的第一個(gè)結(jié)點(diǎn)從備用鏈表中刪除,作為新結(jié)點(diǎn)插入靜態(tài)鏈表。當(dāng)刪除靜態(tài)鏈表中的結(jié)點(diǎn)時(shí),被刪除的結(jié)點(diǎn)插入備用鏈表中,成為備用鏈表的第一個(gè)結(jié)點(diǎn)。之所以從備用鏈表刪除結(jié)點(diǎn)或是插入結(jié)點(diǎn)的操作都在表頭進(jìn)行,是因?yàn)檫@樣的效率最高。

備注:如果不理解備用鏈表,可以參考下面這篇博客:
靜態(tài)鏈表 C實(shí)現(xiàn)

靜態(tài)鏈表和單鏈表的主要區(qū)別

  • 單鏈表的結(jié)點(diǎn)通過(guò) new 關(guān)鍵字產(chǎn)生,結(jié)點(diǎn)被限制在動(dòng)態(tài)存儲(chǔ)區(qū)這個(gè)大范圍內(nèi)。因此,指示結(jié)點(diǎn)位置的指針類型實(shí)際上是常整型。而靜態(tài)鏈表的結(jié)點(diǎn)被限制在靜態(tài)數(shù)組這個(gè)小范圍內(nèi)。因此,指示結(jié)點(diǎn)位置的指針類型(link)一般是整型;
  • 單鏈表不用的結(jié)點(diǎn)通過(guò) delete 關(guān)鍵字釋放,釋放后的結(jié)點(diǎn)由編譯軟件管理。而靜態(tài)鏈表中不用的結(jié)點(diǎn)要自己管理(插入到備用鏈表中)。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,837評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,196評(píng)論 3 414
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,688評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,654評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,456評(píng)論 6 406
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,955評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,044評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,195評(píng)論 0 287
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,725評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,608評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,802評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,318評(píng)論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,048評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,422評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,673評(píng)論 1 281
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,424評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,762評(píng)論 2 372

推薦閱讀更多精彩內(nèi)容