【李木华】线性表
来源:互联网 发布:潍坊全影网络是传销吗 编辑:程序博客网 时间:2024/04/30 16:30
【转】:http://blog.csdn.net/alfa_/article/details/53736853
线性表
- 定义:
- 线性表是由称为元素(element)的数据项组成的一种有限且有序的序列。
- 线性表中不包括任何元素时,称之为空表。当前存储的元素数目称之为线性表的长度(length)。线性表的开始节点称为表头(head),结尾节点称为表尾(tail)。
- 线性表的第一个元素使0来表示的。
- 线性表有两种实现方式:顺序表和链表。
ADT:template <typename E> class List {public: List(){} virtual ~List() {} virtual void append( E& item) = 0; virtual E remove() = 0; virtual void insert() = 0; virtual void moveToStart() = 0; virtual void moveToEnd() = 0; virtual void moveToPos(int pos) = 0; virtual void prev() = 0; virtual void next() = 0; virtual int length() = 0; virtual int currPos() = 0; virtual const E& getValue() const = 0;};
- 顺序表:
AList:template <typename E>class AList :public List < E > {private: int maxSize; //顺序表的最大长度 int listSize; //当前顺序表中的元素个数 int curr; //当前的元素 E* listArray; //数组public: AList(int size = defaultSize){ maxSize = size; listSize = curr = 0; listArray = new E[maxSize]; } ~AList(){ delete[] listArray; } void clear() //清空 { delete[] listArray; listSize = curr = 0; listArray = new E[maxSize]; } 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 moveToStart() { curr = 0; } //移动到开头 void moveToEnd() { curr = listSize; }//移动到结尾 void prev() { if(curr != 0) curr--; } //上一个 void next() { if(curr<listSize) curr++; }//下一个 int length() const { return listSize; } //当前顺序表长度 int currPos() const { return curr; } //当前位置 void append(E& item) //在末尾添加元素 { assert(listSize < maxSize, "List capacity exceeded"); listArray[listSize++] = item; } void moveToPos(int pos) //移动到某一个位置 { assert((pos >= 0) && (pos < listSize), "No element"); curr = pos; } E remove() //删除某一元素{ assert((curr >= 0) && (curr < listSize), "No element"); E it = listArray[curr]; for (int i = curr; i < listSize-1; i++) listArray[i] = listArray[i + 1]; listSize--; return it; } const E& getValue() const //当前位置的值 { assert((curr>0) && (curr < listSize), "No current element"); return listArray[curr]; }};
平均来说,插入和删除要移动一半的元素,即需要Θ(n)时间。
3. 链表:
* 利用指针实现线性表,链表是动态的,它能够按照需要为表中新的元素分配存储空间。
* 链表是由一系列称为表的节点的对象组成的。
* 节点的定义:
Link: template <typename E> class Link {public: E element; //节点的值 Link *next; //指向下一个节点 //构造函数 Link(const E& elemval, Link* nextval = NULL) { element = elemval; next = nextval; } Link(Link* nextval = NULL) { next = nextval; }};
- 链表类的定义:
template<typename E> class LList : public Link < 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 = defaultSize){ init(); } ~LList(){ removeall(); }void print() //打印链表元素 { Link* temp = head->next; for (int i = 0; i < cnt; i++) { cout << temp->element << " "; temp = temp->next; } cout << endl; } void clear(){ removeall(); init(); } void insert(const E& it) { curr->next = new Link<E>(it, curr->next); if (tail == curr) tail = curr->next; cnt++; } void append(const E& it) //添加链表元素 { tail = tail->next = new Link<E>(it, NULL); cnt++; } const E& getValue() const //获取值 { assert(curr->next != NULL, "No value"); return curr->next->element; } E remove() //移除当前节点 { assert(curr->next != NULL, "No Element!"); E it = curr->next->element; Link<E>* ltemp = curr->next; curr->nect = curr->next->next; delete ltemp; cnt--; return it; } void moveToEnd() { curr = head; } void moveToStart() { 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) return; curr = curr->next; } int length() const { return cnt; } int currPos() const //当前结点 { Link<E>* temp = head; int i = 0; while (temp != curr) { temp = temp->next; i++; } return i; } void moveToPos(int pos) //移到当前结点 { assert((pos >= 0) && (pos <= cnt), "position out of range"); curr = head; for (int i = 0; i < pos; i++) curr = curr->next; }};
可利用空间表
Link类能管理自己的可利用空间表(freelist),以取代反复调用的new和delete。可利用空间表存放当前那些不用的线性表,从一个链表中删除的结点就可以放到可利用空间表的首端。当需要把一个新元素增加到链表中时,先检查可利用空间表,看看是否有可用的线性表节点。如果有空结点,则从可利用空间表中取走一个结点。只有当可利用空间表为空时,才会调用标准操作符new。可利用空间表的实现方法:在Link类实现中增加两个新函数,以替代标准的存储分配和回收管理例程new和delete。
链表总结:
数组在内存中是一种连续的数据结构,而链表在内存中是一种不连续的,通过它的定义可以知道,它由一个一个的节点关联组成。以一般的单链表举例,当拿到一个节点的时候,我们可以访问它的下一个节点。要插入一个新节点的时候直接在尾部插入即可。当要修改一个节点的时候,只需要找到它然后直接对它操作。如果需要删除一个节点,就需要找到它的前驱节点,让它的前驱节点指向它的后继节点。这个节点就算被删除了。(严格地说,我们还要考虑待删除的节点所占用的内存,不过这里我们忽略了内存管理的部分)。如下图所示
问题特地把红色箭头及其所能控制的范围标了红色,是想表明,只要得到一个节点,就可以通过该节点中指向下一节点的指针来访问下一节点,只要得到下一节点,就会得到下下一节点,如此类推。这种内容与指针的结合方式,最好使用结构体:
struct Node{ Type element; Node *next;};
而定义链表的时候,只需要把链表的头和尾控制好就行
struct List{ Node *head; Node *tail; int size; ............};
遍历链表的时候,从head开始,一直next找到自己想要的内容即可。
Copyright© by 李木华
Judge by 寒江雪
Date:2016.12.20
#