线性表源码分享(c++),包含顺序表、单链表、循环链表、双向链表

---恢复内容开始---

我是一个c++和数据结构的初学者,本文主要是把清华大学出版社的数据结构(用面向对象方法与c++语言描述)(第2版)这本书中第二章线性表的源码抄下来,在学习的过程中有助于加深印象,书中代码很全,介绍的很仔细。

因为模板类的函数定义好像不能放在源文件中,所以我将代码全部放在一个头文件中(linearList.h),因为使用的少,不好验证代码的可行性,里面可能存在很多错误,如果有朋友发现,希望指出,我好进一步改正。

整个头文件逻辑结构如图

 

因为关于线性表的理论知识比较简单,百度一下一大片,下面就直接上代码,虽然我把它们都放在了同一个头文件中,但是为了后面可以看的更舒服,这里面按照模块把它们拆开

1.线性表类

//线性表抽象类
template <class T>
class LinearList {
public:
    LinearList() {}
    ~LinearList() {}
    virtual int Size()const = 0;
    virtual int Length()const = 0;
    virtual int Search(T& x)const = 0;    //
    virtual int Locate(int i)const = 0;
    virtual bool getData(int i, T& x)const = 0;    
    virtual void setData(int i, T& x) = 0;    //
    virtual bool Insert(int i, T&x) = 0;    //
    virtual bool IsEmpty()const = 0;
    virtual bool IsFull()const = 0;
    virtual void Sort() = 0;
    virtual void input() = 0;
    virtual void output() = 0;
    virtual LinearList<T> operator =(LinearList<T>&L) = 0;
};
View Code

里面似乎少了一个删除操作,不过这只是个父类,在各子类里面都有对应的删除操作,感觉这段代码实际上没什么大用,主要就是向读者说明一般的线性表类应该具备哪些操作。

2.顺序表(顺序表就是个数组,用起来局限性很大)

//顺序表类
const int defaultSize = 100;
template<class T>
class SeqList: public LinearList<T>{
protected:
    T* data;
    int maxSize;
    int last;
    void reSize(int newSize);
public:
    SeqList(int sz = defaultSize);
    SeqList(SeqList<T>& L);
    ~SeqList() { delete[] data; }
    int Size()const { return maxSize; }
    int Length()const { return last + 1; }
    int Search(T&x)const;
    int Locate(int i)const;
    bool getData(int i, T&x)const
    {
        if (i > 0 && i < last + 1) { x = data[i - 1]; return true; }
        else return false;
    }
    void setData(int i, T&x)
    {
        if (i > 0 && i <= last + 1) data[i - 1] = x;
    }
    bool Insert(int i, T&x);
    bool Remove(int i, T&x);
    bool IsEmpty() { return(last == -1 ? true : false;) }
    bool IsFull() { return (last == maxSize - 1) ? true : false; }
    void input();
    void output();
    SeqList<T> operator=(SeqList<T>&L);
};

//顺序表(SeqList)类定义
//构造函数
template<class T>
SeqList<T>::SeqList(int sz) 
{
    if (sz > 0)
    {
        maxSize = sz;
        last = -1;
        data = new T[maxSize];
        if (data = NULL)
        {
            cerr << "存储分配错误!" << endl;
            exit(1);
        }
    }
};

//复制构造函数
template<class T>
SeqList<T>::SeqList(SeqList<T>& L)
{
    maxSize = L.Size;
    last = L.length() - 1;
    T value;
    data = new T[maxSize];
    if(data = NULL)
    {
        cerr << "存储分配错误!" << endl;
        exit(1);
    }
    for (int i = 1; i <= last + 1; i++)
    {
        L.getData(i, value);
        data[i - 1] = value;
    }
};

template<class T>
void SeqList<T>::reSize(int newSize)
{
    if (newSize <= 0)
    {
        cerr << "无效的数组大小" << endl;
        return;
    }
    if (newSize != maxSize)
    {
        T* newarray = new T[newSize];
        if (newarray == NULL)
        {
            cerr << "存储分配错误!" << endl;
            exit(1);
        }
        int n = last + 1;
        T* srcptr = data;
        T* destptr = newarray;
        while (n--) *destptr++ = *srcptr++;
        delete[]data;
        data = newarray;
        maxSize = newSize;
    }
};

//搜索操作
template<class T>
int SeqList<T>::Search(T& x)const
{
    for (int i = 0; i <= last; i++)
    {
        if (data[i] == x)return x + 1;
    }
    return 0;
};

//定位操作
template<class T>
int SeqList<T>::Locate(int i)const
{
    if (i >= 1 && i <= last + 1)return i;
    else return 0;
};

//插入操作
template<class T>
bool SeqList<T>::Insert(int i, T& x)
{
    if (last == maxSize - 1)return false;
    if (i < 0 || i>last + 1)return false;
    for (int j = last; j >= i; j--)
        data[j + 1] = data[j];
    data[i] = x;
    last++;
    return true;
};

//删除操作
template<class T>
bool SeqList<T>::Remove(int i, T&x)    //删除data[i-1],并将x赋值data[i-1]
{
    if (last == -1)return false;
    if (i<1!!i>last + 1)return false;
    x = data[i - 1];
    for (int j = i; j <= last; j++)
    {
        data[j - 1] = data[j];
    }
    last--;
    return true;
};

//输入
template<class T>
void SeqList<T>::input()
{
    cout << "开始建立顺序表,请输入表中元素个数:";
    while (1)
    {
        cin >> last;
        last--;
        if (last <= maxSize - 1)break;
        cout << "表元素个数输入有误,范围不能超过" << maxSize - 1 << ":";
    }
    for (int i = 0; i <= last; i++)
    {
        cin >> data[i]; cout << i + 1 << endl;
    }
};

//输出
template<class T>
void SeqList<T>::output()
{
    cout << "顺序表当前元素的最后位置(last)为:" << last << endl;
    for (int i = 0; i <= last; i++)
    {
        cout << "#" << i + 1: << ":" << data[i] << endl;
    }
};

//赋值
template<class T>
SeqList<T> SeqList<T>::operator=(SeqList<T>&L)
{
    maxSize = L.Size;
    last = L.length() - 1;
    T value;
    data = new T[maxSize];
    if (data = NULL)
    {
        cerr << "存储分配错误!" << endl;
        exit(1);
    }
    for (int i = 1; i <= last + 1; i++)
    {
        L.getData(i, value);
        data[i - 1] = value;
    }
};
//顺序表抽象类定义结束


//顺序表求并集
template<class T>
void SeqList_union(SeqList<T>& LA, SeqList<T>& LB)    //求顺序表的并集,并集结果为存储在LA
{
    int n = LA.length(), m = LB.length(), i, k, x;
    for (i = 1; i <= m; i++)
    {
        LB.getData(i, x);
        k = LA.Search(x);
        if (k == 0)
        {
            LA.Insert(n, x);
            n++;
        }
    }
};

//顺序表求交集
template<class T>
void SeqList_intersection(SeqList<T>& LA, SeqList<T>& LB)    //求顺序表的交集,交集结果存储在LA
{
    int n = LA.Length(), m = LB.Length(), i = 1, k, x;
    while (i <= n)
    {
        LA.getData(i, x);
        k = LB.Search(x);
        if (k == 0)
        {
            LA.Remove(i, x);
            n--;
        }
        else i++;
    }
};
View Code

3.带附加头结点的单链表(我最喜欢的,感觉最有用的)

//单链表类
//带附加头结点的单链表类定义
//结点类定义
template<class T>
struct LinkNode
{
    T data;
    LinkNode<T> *link;
    LinkNode(LinkNode<T> *ptr = NULL) { link = ptr; }
    LinkNode(const T& item, LinkNode<T> *ptr = NULL)
    {
        data = item;
        link = ptr;
    }
};
//链表类定义
template<class T>
class List :public LinearList<T>
{
public:
    List() { first = new LinkNode<T>; }
    List(const T& x) { first = new LinkNode<T>(x); }
    List(List<T>& L);
    ~List() { makeEmpty(); }
    void makeEmpty();
    int Length() const;
    LinkNode<T>* getHead()const { return first; }
    LinkNode<T>* Search(T& x)const;
    LinkNode<T>* Locate(int i)const;
    bool getData(int i, T& x)const;
    void setData(int i, T&x);
    bool Insert(int i, T&x);
    bool Remove(int i, T&x);
    bool IsEmpty()const
    {
        return first->link == Null ? true : false;
    }
    bool IsFull()const { return false; }
    //void Sort();
    //void input();
    void output();
    List<T>& operator= (List<T>&L);
    void inputFront(T endTag);
    void inputRear(T endTag);
protected:
    LinkNode<T> *first;
};

//单链表类(List)定义
//复制构造函数
template<class T >
List<T>::List(List<T>&L)
{
    T value;
    LinkNode<T>*srcptr = L.getHead();
    LinkNode<T>*destptr = first = new LinkNode<T>;
    while (srcptr->link != NULL)
    {
        value = srcptr->link->data;
        destptr->link = new LinkNode<T>(value);
        destptr = destptr->link;
        srcptr = srcptr->link;
    }
    destptr->link = NULL;
};

//将链表置空
template<class T>
void List<T>::makeEmpty()
{
    LinkNode<T> *q;
    while (first->link != NULL)
    {
        q = first->link;
        first->link = q->link;
        delete q;
    }
};

//计算单链表长度
template<class T>
int List<T>::Length()const
{
    LinkNode<T>*p = first->link;
    int count = 0;
    while (p != NULL)
    {
        p = p->link;
        count++;
    }
    return count;
}

//搜索操作
template<class T>
LinkNode<T> *List<T>::Search(T& x)const
{
    LinkNode<T>*current = first->link;
    while (current != NULL)
    {
        if (current->data == x) break;
        else current = current->link;
    }
    return current;
};

//定位操作
template<class T>
LinkNode<T>* List<T>::Locate(int i)const
{
    if (i < 0) return NULL;
    LinkNode<T>*current = first;
    int k = 0;
    while (current != NULL&&k < i)
    {
        current = current->link;
        k++;
    }
    return current;
};

//取值操作
template<class T>
bool List<T>::getData(int i, T&x)const
{
    if (i <= 0) return NULL;
    LinkNode<T>*current = Locate(i);
    if (current == NULL)return false;
    else { x = current->data; return true; }
};

//修改操作
template<class T>
void List<T>::setData(int i, T& x)
{
    if (i <= 0) return;
    LinkNode<T>* current = Locate(i);
    if (current == NULL) return;
    else current->data = x;
};

//插入操作
template<class T>
bool List<T>::Insert(int i, T& x)
{
    LinkNode<T>* current = Locate(i);
    if (current == NULL) return false;
    LinkNode<T>* newNode = new LinkNode<T>(x);
    if (newNode == NULL) { cerr << "存储分配错误!" << endl; exit(1); }
    newNode->link = current->link;
    current->data = newNode;
    return true;
};

//删除操作
template<class T>
bool List<T>::Remove(int i, T&x)
{
    LinkNode<T>* current = Locate(i - 1);
    if (current == NULL || current->link == NULL) return false;
    LinkNode<T>*del = current->link;
    current->link = del->link;
    x = del->data;
    delete del;
    return true;
};

//输出
template<class T>
void List<T>::output()
{
    LinkNode<T> * current = first->link;
    while (current != NULL)
    {
        cout << current->data << endl;
        current = current->link;
    }
};

//赋值操作
template<class T>
List<T>&  List<T>::operator=(List<T>& L)
{
    T value;
    LinkNode<T>* srcptr = L.getHead();
    LinkNode<T>* destptr = first = new LinkNode<T>;
    while (srcptr->link != NULL)
    {
        value = srcptr->link->data;
        destptr->link = new LinkNode<T>(value);
        destptr = destptr->link;
        srcptr = srcptr->link;
    }
    destptr->link = NULL;
    return *this;
};

//前插法建立单链表
template<class T>
void List<T>::inputFront(T endTag)    //endTag为输入序列结束标志
{
    LinkNode<T>* newNode;
    T val;
    makeEmpty();
    cin >> val;
    while (val != endTag)
    {
        newNode = new LinkNode<T>(val);
        if (newNode == NULL) { cerr << "存储分配错误!" << endl; exit(1); }
        newNode->link = first->link;
        first->link = newNode;
        cin >> val;
    }
};

//后插法建立单链表
template<class T>
void List<T>::inputRear(T endTag)
{
    LinkNode<T>* newNode, *last;
    T val;
    makeEmpty();
    cin >> val;
    last = first;
    while (val != endTag)
    {
        newNode = new LinkNode<T>(val);
        if (newNode == NULL) { cerr << "内存分配错误!" << endl; exit(1); }
        last->link = newNode;
        last = newNode;
        cin >> val;
    }
    last->link = NULL;
}
View Code

4.循环链表(循环链表书中只有类的声明,具体的函数实现是自己写的,所以可能存在错误)

//循环链表类定义
template<class T>
struct CircLinkNode    //链表结点类定义
{
    T data;
    CircLinkNode<T> *link;
    CircLinkNode(CircLinkNode<T> *next = NULL) :link(next) {}
    CircLinkNode(T d, CircLinkNode<T> *next = NULL) :data(d), link(next) {}
};

template<class T>
class CircList    //链表类定义
{
public:
    CircList();
    CircList(CircList<T>& L);
    ~CircList();
    int Length()const;
    bool IsEmpty()
    {
        return first->link == first ? true : false;
    }
    CircLinkNode<T> *getHead() const {return first};
    void setHead(CircLinkNode<T> *p);
    CircLinkNode<T> *Search(T x);
    CircLinkNode<T> *Locate(int i);
    T* getData(int i);
    void setData(int i, T&x);
    bool Insert(int i, T&x);
    bool Remove(int i, T&x);
    CircLinkNode<T> *first, *last;
};

//循环链表
template<class T>
CircList<T>::CircList()
{
    first = new CircLinkNode<T>;
    if (first == NULL) { cerr << "内存分配错误!" << endl; exit(1); }
    first->link = first;
    last = first->link;
}

template<class T>
CircList<T>::CircList(CircList<T>& L)
{
    T value;
    CircLinkNode<T> *srcptr0 = L.getHead();
    CircLinkNode<T> *srcptr = srcptr0->link;
    CircLinkNode<T> *destptr = first = new CircLinkNode<T>;
    if(first==NULL) { cerr << "内存分配错误!" << endl; exit(1); }
    while (srcptr->link != srcptr0->link)
    {
        value = srcptr->data
        destptr->link = new CircLinkNode<T>(value);
        if (destptr->link == NULL) { cerr << "内存分配错误!" << endl; exit(1); }
        srcptr = srcptr->link;
        destptr = destptr->link;
    }
    last= destptr->link;
    last->link = first->link;
}


template<class T>
CircList<T>::~CircList()
{
    CircLinkNode<T> *q;
    while (first->link != NULL)
    {
        q = first->link;
        if (q->link != q) { first->link = q->link;  delete q; }
        else { delete q; first->link = NULL; }
    }
}

template<class T>
int CircList<T>::Length()const
{
    CircLinkNode<T> *q = first->link;
    int count = 1;
    while (q->link != first->link)
    {
        q = q->link;
        count++;
    }
    return count;
}

template<class T>
void CircList<T>::setHead(CircLinkNode<T> *p)
{
    p->link = first->link;
    first = p;
}

template<class T>
CircLinkNode<T> *CircList<T>::Search(T x)
{
    CircLinkNode<T>* current = first->link;
    if (current->data == x) return current;
    current = current->link;
    while (current != first->link)
    {
        if (current->data == x)
        {
            return current;
        }
        else current = current->link;
    }
    return NULL;
}

template<class T>
CircLinkNode<T> *CircList<T>::Locate(int i)
{
    if (i < 0) return NULL;
    CircLinkNode<T>* current = first;
    int k = 0;
    while (k < i)
    {
        current = current->link;
        k++;
    }
    return current;
}

template<class T>
T* CircList<T>::getData(int i)
{
    if (i <= 0) return NULL;
    CircLinkNode<T>* current = Locate(i);
    return current->data;
}

template<class T>
void CircList<T>::setData(int i, T&x)
{
    if (i <= 0) return NULL;
    CircLinkNode<T>* current = Locate(i);
    current->data = x;
}

template<class T>
bool CircList<T>::Insert(int i, T&x)
{
    if (i < 0) return NULL;
    else if (i == 0)
    {
        CircLinkNode<T>* current = first;
        if (current == NULL) return false;
        CircLinkNode<T> *newNode = new CircLinkNode<T>(x);
        if (newNode == NULL) { cerr << "内存分配错误!" << endl; exit(1); }
        current->link = newNode;
        newNode->link = newNode;
        if (current == last) last = newNode;
        return true;
    }
    else
    {
        CircLinkNode<T>* current = Locate(i);
        if (current == NULL) return false;
        CircLinkNode<T> *newNode = new CircLinkNode<T>(x);
        if (newNode == NULL) { cerr << "内存分配错误!" << endl; exit(1); }
        newNode->link = current->link;
        current->link = newNode;
        if (current == last) last = newNode;
        return true;
    }
}

template<class T>
bool CircList<T>::Remove(int i, T&x)
{
    if (i <= 0) return NULL;
    CircLinkNode<T>* current = Locate(i-1);
    if (current == NULL) return false;
    CircLinkNode<T> *del = current->link;
    current->link = del->link;
    if (del == last) last = current;
    x = del->data;
    delete del;
    return true;
}
View Code

 书中带附加头结点的循环链表是这样的

个人不太喜欢循环链表带附加头结点,因为在求解约瑟夫问题(后面有该问题的代码测试)时感觉这个附加头结点很烦人,又奈何书中在循环链表类的定义中又有与附加头结点相关的操作,所以我把循环链表设计成了

 

反正只是为了学习,真正的好不好用不需要太在意,根本用不上。

求解约瑟夫问题:一个旅行社要从n个旅客中选出一名旅客,为他提供免费的环球旅行服务。旅行社安排这些旅客围成一个圆圈,从帽子中取出一张纸条,用上面写的正整数m(<n)作为报数值。游戏进行时,从第一个人开始按顺时针方向自1开始顺序报数,报到m时停止报数,报m的人被淘汰出列,然后下一个人重新报数,如此下去直到圆圈中只剩下一个人,这个人为胜利者。假设n=8,m=3,则出列顺序为3,6,1,5,2,8,4,最后7号胜出。

约瑟夫函数

//求解Josephus问题
template<class T>
void Josephus(CircList<T>& Js, int n, int m)    
{
    CircLinkNode<T> *p = Js.Locate(1), *pre = NULL;
    for (int i = 0; i < n - 1; i++)
    {
        for (int j = 1; j < m; j++)
        {
            pre = p;
            p = p->link;
        }
        cout << "出列的人是" << p->data << endl;
        pre->link = p->link;
        delete p;
        p = pre->link;
    }
    Js.first->link = Js.last = p;
}
View Code

约瑟夫问题调试

#include<iostream>
#include"linearList.h"
using namespace std;

int main()
{
    CircList<int> clist;
    int i, n, m;
    cout << "输入游戏者人数和报数间隔:" << endl;
    cin >> n >> m;
    for (i = 1; i <= n; i++) 
        clist.Insert(i-1, i);
    Josephus(clist, n, m);

    system("pause");
    return 0;
}
View Code

5.双向链表

//双向链表类定义(带附加头结点)
//双向链表结点类定义
template<class T>
struct DblNode
{
    T data;
    DblNode<T>* lLink, *rLink;    //链表前驱后继指针
    DblNode(DblNode<T>* left = NULL, DblNode<T>* right = NULL) :lLink(left), rLink(right) {}
    DblNode(T value, DblNode<T>* left = NULL, DblNode<T>* right = NULL):data(value,)lLink(left), rLink(right) {}
};

//双向链表类定义
template<class T>
class DblList :public LinearList<T>
{
public:
    DblList(T uniqueVal);    //构造函数,建立附加头结点
    //~DblList();    //析构函数
    int Length() const;
    bool IsEmpty() { return first->rlink == first; } //判断链表是否为空
    DblNode<T>* getHead() const { return first; }
    void setHead(DblNode<T>* ptr) { first = ptr; }    //设置附加头结点地址;书中是这么定义的,但是这样岂不是把链表丢弃了?
    DblNode<T>* Search(const T& x);    //在链表中沿后继方向寻找等于给定值x的结点
    DblNode<T>* Locate(int i, int d);    //在链表中定位序号为i(>=0)的结点,d=0按前驱方向,d!=0按后继方向
    bool Insert(int i, const T& x, int d);    //在第i个结点后插入一个包含有值x的新结点,d=0按前驱方向,d!=0按后继方向
    bool Reomve(int i, T&x, int d);    //删除第i个结点,x返回其值,d=0按前驱方向,d!=0按后继方向
private:
    DblNode<T>* first;
};

template<class T>
DblList<T>::DblList(T uniqueVal)
{
    first = new DblNode<T>(uniqueVal);
    if (first == NULL) { cerr << "内存分配错误!" << endl; exit(1); }
    first->rLink = first->lLink = first;
}

template<class T>
int DblList<T>::Length()const
{
    DblNode<T>* current = first->rLink;
    int count = 0;
    while (current != first)
    {
        current = current->rLink;
        count++;
    }
    return count;
}

template<class T>
DblNode<T>* DblList<T>::Search(const T& x)
{
    DblNode<T> *current = first->rLink;
    while (current != first && current->data != x) current = current->rLink;
    if (current != first) return current;    //搜索成功
    else return NULL;    //搜索失败
}

template<class T>
DblNode<T>* DblList<T>::Locate(int i, int d)
{
    if (first->rLink == first || i == 0) return first;
    DblNode<T>* current;
    if (d == 0) current = first->lLink;
    else current = first->rLink;
    for (int j = 1; j < i; j++)
    {
        if (current == first) break;    //链表太短
        else if (d == 0) current = first->lLink;
        else current = first->rLink;
    }
    if (current != first) return current;    //搜索成功
    else return NULL;    //搜索失败
}

template<class T>
bool DblList<T>::Insert(int i, const T&x, int d)
{
    DblNode<T>* current = Locate(i, d);
    if (current == NULL) return false;
    DblNode<T>* newNode = new DblNode<T>(x);
    if (newNode == NULL) { cerr << "内存分配错误!" << endl; exit(1); }
    if (d == 0)
    {
        newNode->lLink = current->lLink;
        current->lLink = newNode;
        newNode->lLink->rLink = newNode;
        newNode->rLink = current;
    }
    else
    {
        newNode->rLink = current->rLink;
        current->rLink = newNode;
        newNode->rLink->lLink = newNode;
        newNode->lLink = current;
    }
}

template<class T>
bool DblList<T>::Reomve(int i, T& x, int d)
{
    DblNode<T>* current = Locate(i, d);
    if (current == NULL) return false;
    current->rLink->lLink = current->lLink;
    current->lLink->rLink = current->rLink;
    x = current->data;
    delete current;
    return true;
}
View Code

感觉整个线性表这一章,单链表让人最舒服,其它几类虽然看上去不那么自然,但是主要目的是学习其中的逻辑结构。

 

转载于:https://www.cnblogs.com/dengmingtian/p/10940184.html

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值