线性结构(Linear Structure)—— List、Stack、Queue
线性结构反映节点之间的逻辑关系是一对一的
可表示为:
: Head; : Tail; : 的直接前驱; : 的直接后继;n = 0时为空表;
线性表(linear list):是具有相同特性的数据元素的一个有限序列
ADT(Abstract Data Type):抽象数据类型,是哟个实现包括储存元素的存储结构以及实现基本操作的算法。
这里,数据类型的定义和它的实现是分开的,如抽象类(virtual)、类模板(template)。
an ADT for a list:
(这是一个抽象类的类模板,因此继承它的所有类和类模板都必须实现它的全部抽象方法)
template <typename E> class List { // the ADT for a list
private:
void operator =(const List&) {} // Protect assignment
List(const List&) {} // Protect copy constructor
public:
List() {} // Default constructor
virtual ˜List() {} // Base destructor
virtual void clear() = 0;
virtual void insert(const E& item) = 0;
virtual void append(const E& item) = 0;
virtual E remove() = 0;
virtual void moveToStart() = 0;
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;
};
遍历一个list / 查找一个元素:
bool find(List<int>& L, int K) {
int it;
for (L.moveToStart(); L.currPos()<L.length(); L.next()) {
it = L.getValue();
if (K == it)
return true;
} return false;
}
两种典型的List的实现
1. 顺序表(Array-based List)——— 在程序中,叫做“AList”, 继承于class List
把list中的所有元素按照顺序存储方法,依次存储到存储器中一片连续的存储空间中。
在List对象被创建时就要知道它的大小:n*sizeof(ElemType)
先上代码,讲解在后:
template <typename E> class AList : public List<E> {
private:
int maxSize; // Maximum size of list
int listSize; // Number of list items now
int curr; // Position of current element
E* listArray; // Array holding list elements
public:
AList(int size = defaultSize) { // Constructor
maxSize = size;
listSize = curr = 0;
listArray = new E[maxSize];
}
˜AList() { delete[] listArray; } // Destructor
void clear() { // Reinitialize the list
delete[] listArray; // Remove the array
listSize = curr = 0; // Reset the size
listArray = new E[maxSize]; // Recreate array
}
void insert(const E& it) { // Insert "it" at current position
assert(listSize < maxSize, "List capacity exceeded"); //assert:如果不满足前面的条件,则返回这串文字
for (int i = listSize; i > curr; i--) // Shift elements up
listArray[i] = listArray[i - 1]; // to make room
listArray[curr] = it;
listSize++; // Increment list size
}
void append(const E& it) { // Append "it"
assert(listSize < maxSize, "List capacity exceeded");
listArray[listSize++] = it;
}
E remove() { // Remove and return the current element.
assert((curr >= 0) && (curr < listSize), "No element");
E it = listArray[curr]; // Copy the element
for (int i = curr; i < listSize - 1; i++) // Shift them down
listArray[i] = listArray[i + 1];
listSize--; // Decrement size
return it;
}
void moveToStart() { curr = 0; } // Reset position
void moveToEnd() { curr = listSize; } // Set at end
void prev() { if (curr != 0) curr--; } // Back up
void next() { if (curr < listSize) curr++; } // Next
int length() const { return listSize; } // Return list siz
int currPos() const { return curr; } // Return current position
void moveToPos(int pos) { // Set current list position to "pos"
assert ((pos>=0)&&(pos<=listSize), "Pos out of range");
curr = pos;
}
const E& getValue() const { // Return current element
assert((curr>=0)&&(curr<listSize),"No current element");
return listArray[curr];
}
};
Insert方法:时间复杂度与 ListSize和插入的位置都有关,最好,最坏。
平均:共有(n+1)个位置可以插入元素,需要移动0~n个元素:平均n/2
Insert方法的时间复杂度为:
remove方法:原理同Insert方法,时间复杂度为
除Insert、remove、constructor、destructor、clear外,其他方法时间复杂度为
顺序存储结构的问题:存储空间分配不灵活;运算的空间复杂度高