线性表学习总结(顺序表和链表)

线性表主要分为两种,顺序表和链表。
顺序表主要利用的是数组,大部分时候只需要重新定义数组的插入或删除操作就可以,所以顺序表的存储结构跟数组是相同的,都是一串连在一起的内存。因此,顺序表在存储数据的同时也保存了数据之间的逻辑关系。并且可以通过访问数组下标直接访问对应元素。这里主要总结链表。
链表是将内存中零散的不连续的部分连接在一起,这个起连接作用的东西就是指针。我们可以用过指针去访问已知的可以访问的地址,这就好比侦探游戏,如果没有明确的线索,再聪明的侦探也没办法接近真相,而对于链表的设计者而言,指针就是线索,失去了指针,链表也就没办法延续下去。
为了同时存储数据和逻辑关系,需要把这两部分整合到一起,Node结构体应运而生。

template<typename T>
struct Node
{
	T data;
	Node<T>*next;
};

在这里我们用到了模板,这么做可以让代码的服用程度更高,不做过多解释。
在Node的定义中不难看出,Node本身包含一个指向自身类型的指针,具体的可以说指针next指向下一个节点Node。
图为节点结构示意图在使用链表前,应该先创建链表。
创建链表分为两种,带头结点与不带头节点的创建,而这唯一的区别就是,头指针First指向的Node型内存中是否有具体的数据。如果有就是不带头结点的创建方式,此时链表是有一个元素的,反之就是带头结点的创建方式。但是它们的next均指向NULL(也就是空悬),至此我们完成了空链表的创建。稍加思考不难发现,带头结点的创建方式可以将空表与非空表的创建统一起来,更加方便(这不绝对,视情况而定)。
具体代码实现如下:

template <typename T>
class LinkList
{
    private:
    Node<T>* first;
    public:
    LinkList();//
    LinkList(T a[],int n);//
    LinkList(T a[],int n,int tail);//
    ~LinkList();//
    int Length();//
    T LocationFind(int i);//
    int ValueFind(T value);//
    void Insert(int i,T x);
    T LocationDelete(int n);//
    int ValueDelete(T x);//
    bool Empty();
    void Print();
};
template <typename T>
LinkList<T>::LinkList()
{
    first = new Node<T>;
    first->next = NULL;
}

first指针是指向第一个节点的必备指针,如果没有first,链表就无迹可寻,简单地讲,我们把链表弄丢了。
创建完空表后我们就可以进行插入了,当然也可以写一个非空表的创建,不过这些操作都可以用插入代替。不同于顺序表,链表需要依次处理每个节点,这是其分布结构决定的,也是区别于顺序表最大的不同。我们可以选择按值插入或者按地址插入,不过这都需要先找到符合条件的指针,因此设置工作指针p,p从头节点开始遍历链表,通过p = p->next 进行后移,直到链表结束或者找到符合条件的节点。
具体代码实现如下:

cpp
template<typename T>
void LinkList<T>::Insert(int n,T x)
{
    Node<T>* p = first;
    int counts = 0;
    while(p->next!=NULL&&counts<n-1)
    {
        p = p->next;
        counts++;
    }
    if(p->next==NULL) throw "插入位置错误";
    else{
        Node<T>* q = new Node<T>;
        q->data = x;
        q->next = p->next;
        p->next = q;
    }
}


查找操作其实就是插入操作的一部分,同样可以分为按值查找和按地址查找。
具体代码实现如下:

template <typename T>
T LinkList<T>::LocationFind(int i)
{
    Node<T>* p = first->next;
    int counts = 0;
    while(p!=NULL&&counts<i-1)
    {
        p = p->next;
        counts++;
    }
    if(p==NULL) return -1;
    else return p->data;
}
template <typename T>
int LinkList<T>::ValueFind(T x)
{
    Node<T>* p = first->next;
    int counts = 1;
    while(p!=NULL)
    {
        if(p->data==x) return counts;
        else{
                p = p->next;
                counts++;
        }
    }
    return -1;
}

删除操作是在查找操作的前提下进行的,只需要地址删除就足够了,因为按值查找返回的就是地址,可以调用其获取。
具体代码实现如下:

template <typename T>
T  LinkList<T>::Delete(int n)
{
    T x;
    Node<T> *p = first, *q = NULL; //工作指针p指向头结点
    int count = 0;
    while (p != NULL && count < n - 1) //查找第i-1个结点
    {
        p = p->next;
        count++;
    }
    if (p == NULL || p->next == NULL || n == 0) //结点p不存在或p的后继结点不存在
    return -1;
    //throw "Error";
    else {
            q = p->next; x = q->data; //暂存被删结点
            p->next = q->next; //摘链
            delete q;
            return x;
        }
}

定义完增删查改后,其他操作都可以在此基础上进行。
最后是链表的析构,设置工作指针,依次后移,直至链表为空,并回收内存。
具体代码实现如下:

template <typename T>
LinkList<T>::~LinkList()
{
    Node<T>* p = first;
    while(first->next!=NULL)
    {
        first = first->next;
        delete p;
        p = first;
    }
}

回收内存十分重要,不可省略。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章