線性表的兩種實現 -- 順序表和連結串列(C++)
阿新 • • 發佈:2019-02-16
線性表抽象類宣告
#ifndef ADT_H
#define ADT_H
//線性表ADT
template <typename E>
class List{
private:
void operator =(const List){} //賦值運算子
List(const List&){} //複製建構函式
public:
List(){} //預設建構函式
virtual ~List(){} //解構函式
//清空所有元素
virtual void clear() = 0;
//在當前位置插入元素item
virtual void insert(const E& item) = 0;
//list尾部新增一個元素
virtual void append(const E& item) = 0;
//刪除並返回當前位置的元素
virtual E remove() = 0;
//設定當前位置為list的開始位置
virtual void moveToStart() = 0;
//設定當前位置為list的末尾位置
virtual void moveToEnd() = 0;
//當前位置左移一個位置,不改變元素
virtual void prev() = 0;
//當前位置右移一個位置,不改變元素
virtual void next() = 0;
//返回元素數量--即獲取長度
virtual int length() const = 0;
//返回當前元素位置
virtual int currPos() const = 0;
//設定當前位置
virtual void moveToPos(int pos) = 0;
//獲取當前元素
virtual const E& getValue() const = 0;
};
#endif
順序表的實現
#include "ADT.h"
template <typename E>
class AList : public List<E>{
private:
int maxSize; //list 最大容量
int listSize; //list 當前元素個數
int curr; //當前元素位置
E* listArray; //list指標
public:
AList(int size = defaultSize){ //建構函式
maxSize = size;
listSize = curr = 0;
listArray = new E[maxSize];
}
~AList(){ delete[] listArray; } //解構函式
void clear(){ //重新初始化list
delete [] AList;
listSize = 0;
listArray = new E[maxSize];
}
//在當前位置插入 it 元素
void insert(const E& it){
Assert(listSize < maxSize, "List capacity exceeded");
for (int i = listSize; i > curr; i--)
listArray[i] = listArray[i - 1];
listArray[curr] = it;
listSize++;
}
//末尾新增元素
void append(const E& it){
Assert(listSize < maxSize, "List capacity exceeded");
listArray[listSize++] = it;
}
//刪除並返回當前位置的元素
E remove(){
Assert(listSize < maxSize, "List capacity exceeded");
E it = listArray[curr];
for (int i = curr; i < listSize - 1; i++)
listArray[i] = listArray[i + 1];
listSize--;
return it;
}
void moveToStart(){ curr = 0; } //位置重置為start位置
void moveToEnd(){ curr = listSize; } //位置重置為end位置
void prev(){ if (curr != 0) curr--; }; //上一個元素位置
void next(){ if (curr < listSize) curr++ }; //下一個元素位置
//返回list元素個數
int length() const { return listSize };
//返回當前元素位置
int currPos() const { return curr };
//設定當前list位置為 pos
void moveToPos(int pos){
Assert((pos >= 0) && (pos <= listSize), "pos out of range");
curr = pos;
}
//獲取當前位置元素
const E& getValue() const {
Assert((curr >= 0) && (curr <= listSize), "No current element");
return listArray[curr];
}
};
單鏈表的實現
#include "ADT.h"
//單鏈表結點定義
template <typename E>
class Link{
public:
E element; //節點的值
Link* next; //next
Link(const E& elemval, Link* nextval = NULL){
element = elemval;
next = nextval;
}
Link(Link* nextval = NULL){
next = nextval;
}
};
template <typename E>
class LList: public List<E>
{
private:
Link<E>* head;
Link<E>* tail;
Link<E>* curr;
int cnt;
//初始化
void init(){
curr = tail = head = new Link<E>;
cnt = 0;
}
//清空所有元素
void removeall(){
while (head != NULL){
curr = head;
head = head->next;
delete curr;
}
}
public:
LList(int size = defalueSize){ init(); } //建構函式
~LList(){ removeall(); } //解構函式
void print() const; //print List
void clear(){ removeall(); init(); } //clear List
void insert(const E& it){
curr->next = new Link<E>(it, curr->next);
if (tail == currr)
tail = curr->next;
cnt++;
}
void append(const E& it){
tail = tail->next = new Link<E>(it, NULL);
cnt++;
}
E remove(){
Assert(curr->next != NULL, "No element");
E it = curr->next->element; //儲存資料
Link<E>* ltemp = curr->next; //儲存連結串列節點
if (tail == curr->next) tail = curr; //重置尾節點
curr->next = curr->next->next; //刪除節點
delete ltemp; //釋放空間
cnt--; //cnt - 1
return it;
}
//移動至連結串列開始位置
void moveToStart(){ curr = head; }
//移動至連結串列尾端
void moveToEnd(){ curr = tail; }
//上一個節點
void prev(){
if (curr == head) return;
Link<E>* temp = head;
while (temp->next != curr){
temp = temp->next;
}
curr = temp;
}
//下一個節點
void next(){
if (curr != tail)
curr = curr->next;
}
//返回長度
int length() const { return cnt; }
//連結串列當前位置
int currPos() const{
Link<E>* temp = head;
int i;
for (i = 0; curr != temp; i++){
temp = temp->next;
}
return i;
}
//移動至連結串列的pos位置
void moveToPos(int pos){
Assert((pos >= 0) && (pos <= cnt), "Pos out of range");
curr = head;
for (int i = 0; i < pos; i++)
curr = curr->next;
}
//獲取當前元素
const E& getValue() const {
Assert(curr->next != NULL, "No Value");
return curr->next->element;
}
};
線性表兩種實現方法的比較
空間方面:
順序表的缺點:大小事先固定。雖然便於分配空間,但是元素只有少數的幾個時造成空間的浪費。
連結串列的優點:只有實際在連結串列中的物件需要空間,只要存在可用的記憶體空間分配,連結串列中元素的個數沒有限制。
順序表的優點是對於表中的每一個元素沒有浪費空間,而連結串列需要在每個節點附加上一個指標。在可以大概估計出線性表長度的情況下,順序表比連結串列有更高的空間效率。
隨機訪問元素:
取出線性表中第i個元素這樣的按位置隨機訪問,使用順序表更快些;通過next和prev可以很容易調整當前位置向前或向後,這兩種操作需要的時間為O(1)。
相比之下,單鏈表不能直接訪問前面的元素,按位置只能從表頭(或者當前位置)開始,直到找到那個特定的位置。假定表中每個位置是由prev和moveToPos平均訪問到的,那麼訪問線性表第i個元素的操作所需的平均情況下時間和最差情況下時間都是O(n)。
插入和刪除元素:
給出指向連結串列中合適位置的指標後,insert和remove函式所需要的時間僅為O(1)。
而順序表必須在陣列內將其餘元素向前或向後移動。這種方法所需的平均情況下時間和最差時間均為O(n)。
對於許多應用,插入和刪除是最主要的操作,因此他們的時間效率是舉足輕重的。僅就這個原因而言,連結串列往往比順序表更好。