线性表作为一种线性数据结构,常应用于信息检索,存储管理等诸多领域,因此了解线性表的基本操作与应用对于我们学习数据结构有着十分重要的意义。

一,线性表的基本操作

首先,我们定义一个线性表的基类linearlist,并以此定义了它的派生类顺序表类seqlist和链表类singlelist.在基类中,我们以抽象函数的形式定义了线性表常用的几种操作,如插入删除等。

线性表的基本操作Java 线性表的基本操作有_链表

线性表的基本操作Java 线性表的基本操作有_链表_02

#ifndef LINEARLIST_H_INCLUDED
#define LINEARLIST_H_INCLUDED
#include<iostream>
using namespace std;
template<class T>
class Linearlist
{
public:
    virtual bool IsEmpty() const=0;
    virtual int Length()const=0;
    virtual bool Find(int i,T&x)const=0;
    virtual  int Search(T x)const=0;
    virtual bool Insert(int i,T x)=0;
    virtual bool Delete(int i)=0;
    virtual bool Update(int i,T x)=0;
    virtual void Output(ostream& out)const=0;
protected:
    int n;
};
#endif // LINEARLIST_H_INCLUDED

View Code

顺序表是用一组连续的地址来存储元素,就像数组一样,但顺序表的长度可以随着插入删除操作的长度而变化。顺序表类seqlist中封装了两个私有成员maxlength和elements,同时也继承了基类中的各个操作函数。

线性表的基本操作Java 线性表的基本操作有_链表

线性表的基本操作Java 线性表的基本操作有_链表_02

#ifndef SEQLIST_H_INCLUDED
#define SEQLIST_H_INCLUDED
#include"linearlist.h"
template<class T>
class SeqList:public Linearlist<T>
{
public:
    SeqList(int mSize);
    ~SeqList()
    {
        delete[] elements;
    }
    bool IsEmpty() const;
    int Length() const;
    bool Find(int i,T& x)const;
    int Search(T x)const;
    bool Insert(int i,T x);
    bool Delete(int i);
    bool Update(int i,T x);
    void Output(ostream &out)const;
private:
    T *elements;
    int maxLength;
    int n;
};
template<class T>
SeqList<T>::SeqList(int mSize)
{
    maxLength=mSize;
    elements=new T[maxLength];
    n=0;
}
template<class T>
bool SeqList<T>::IsEmpty() const
{
    return n==0;
}
template<class T>
int SeqList<T>::Length() const
{
    return n;
}
template<class T>
bool SeqList<T>::Find(int i,T &x)const
{
    if(i<0||i>n-1)
    {
        cout<<"out of bounds!\n";
        return false ;
    }
    x=elements[i];
    return true;
}
template<class T>
int SeqList<T>::Search(T x) const
{
    for(int i=0;i<n;i++)
    {
        if(elements[i]==x)
            return i;
    }
    return -1;
}
template<class T>
bool SeqList<T>::Insert(int i,T x)
{
    if(i<-1||i>n-1)
    {
        cout<<"out of bounds\n";
        return false;
    }
    if(n==maxLength)
    {
        cout<<"OverFlow!\n";
        return false;
    }
    for(int j=n-1;j>i;j--)
        elements[j+1]=elements[j];
    elements[i+1]=x;
    n++;
    return true;
}
template<class T>
bool SeqList<T>::Delete(int i)
{
    if(!n)
    {
        cout<<"UnderFlow\n";
        return false;
    }
    if(i<0||i>n-1)
    {
        cout<<"out of bounds\n";
        return false;
    }
    for(int j=i+1;j<n;j++)
        elements[j-1]=elements[j];
    n--;
    return true;

}
template<class T>
bool SeqList<T>::Update(int i,T x)
{
    if(i<0||i>n-1)
    {
        cout<<"out of bounds\n";
        return false;
    }
    elements[i]=x;
    return true;
}
template<class T>
void SeqList<T>::Output(ostream &out)const
{
    for(int i=0;i<n;i++)
        out<<elements[i]<<' ';
    out<<endl;
}

#endif // SEQLIST_H_INCLUDED

View Code

同样是作为线性表的派生类,与顺序表不同的是,链表存储空间利用率高,可随意存取元素,但是遇到插入删除操作频繁的应用,效率将会降低。常见的链表有单链表,双链表,循环链表等,这里只讲单链表。

单链表中,每个元素占用一个节点Node,每个节点有两个域组成:存放元素的数据域element和存放后继节点的地址的指针域link。

线性表的基本操作Java 线性表的基本操作有_链表

线性表的基本操作Java 线性表的基本操作有_链表_02

#ifndef SINGLELIST_H_INCLUDED
#define SINGLELIST_H_INCLUDED
#include"linearlist.h"
template<class T> class SingleList;
template<class T>
class Node
{
protected:
    T element;
    Node<T> *link;
    friend class SingleList<T>;
};
template<class T>
class SingleList:public Linearlist<T>
{
public:
    SingleList()
    {
        first=NULL;
        n=0;
    }
    ~SingleList();
    bool IsEmpty() const;
    int Length() const;
    bool Find(int i,T& x)const;
    int Search(T x)const;
    bool Insert(int i,T x);
    bool Delete(int i);
    bool Update(int i,T x);
    void Output(ostream &out)const;
    void Clear();
protected:
    Node<T> *first;
    int n;
};
template<class T>
SingleList<T>::~SingleList()
{
    Node<T> *p;
    while(first)
    {
        p=first->link;
        delete first;
        first=p;
    }
}
template<class T>
bool SingleList<T>::IsEmpty() const
{
    return n==0;
}
template<class T>
int SingleList<T>::Length() const
{
    return n;
}
template<class T>
bool SingleList<T>::Find(int i,T& x)const
{
    if(i<0||i>n-1)
    {
        cout<<"out of bounds\n";
        return false;
    }
    Node<T> *p=first;
    for(int j=0;i<i;j++)
    {
        p=p->link;
    }
    x=p->element;
    return true;

}
template<class T>
int SingleList<T>::Search(T x)const
{
    Node<T> *p=first;
    int j;
    for(j=0;p&&p->element!=x;j++)
        p=p->link;
    if(p)
        return j;
    return -1;
}
template<class T>
bool SingleList<T>::Insert(int i,T x)
{
    if(i<-1||i>n-1)
    {
        cout<<"out of bounds\n";
        return false;
    }
    Node<T> *q=new Node<T>;
    q->element=x;
    Node<T> *p=first;
    for(int j=0;j<i;j++)
    {
        p=p->link;
    }
    if(i>-1)
    {
        q->link=p->link;
        p->link=q;
    }
    else
    {
        q->link=first;
        first=q;

    }
    n++;
    return true;
}
template<class T>
bool SingleList<T>::Delete(int i)
{
    if(!n)
    {
        cout<<"UnderFlow\n";
        return false;
    }
    if(i<0||i>n-1)
    {
        cout<<"out of bounds\n";
        return false;
    }
    Node<T>*p=first,*q=first;
    for(int j=0;j<i-1;j++)
        q=q->link;
    if(i==0)
        first=first->link;
    else
    {
        p=q->link;
        q->link=p->link;

    }
    delete p;
    n--;
    return true;
}
template<class T>
bool SingleList<T>::Update(int i,T x)
{
    if(i<0||i>n-1)
    {
        cout<<"out of bounds\n";
        return false;
    }
    Node<T> *p=first;
    for(int j=0;j<i;j++)
        p=p->link;
    p->element=x;
    return true;

}
template<class T>
void SingleList<T>::Output(ostream &out)const
{
    Node<T> *p=first;
    while(p)
    {
        out<<p->element<<" ";
        p=p->link;
    }
    out<<endl;
}
#endif // SINGLELIST_H_INCLUDED

View Code

主函数里面我们定义了一个顺序表类和一个链表类,演示了基本的插入删除操作,运行结果如图:

线性表的基本操作Java 线性表的基本操作有_链表

线性表的基本操作Java 线性表的基本操作有_链表_02

#include <iostream>
#include"seqlist.h"
#include"singlelist.h"
using namespace std;
const int SIZE=20;
int main()
{
    SeqList<int> LA(SIZE);
    for(int i=0;i<5;i++)
        LA.Insert(i-1,i);
    SingleList<int> LB;
    for(int i=0;i<5;i++)
        LB.Insert(i-1,i*2);
    cout<<"LA:";
    LA.Output(cout);
    cout<<"LB:";
    LB.Output(cout);
    cout<<"delete LA's last member:\n";
    LA.Delete(4);
    cout<<"LA:";
    LA.Output(cout);
    cout<<"insert a number at the begining of LB:\n";
    LB.Insert(-1,6);
    cout<<"LB:\n";
    LB.Output(cout);
    return 0;
}

View Code 

线性表的基本操作Java 线性表的基本操作有_线性表_09

二,线性表的应用

线性表的应用非常广泛,作为线性表的一个应用的例子,我们讨论一元整系数的加法和乘法操作。

多项式的每一项都有系数和指数组成,所以我们设计了项节点Term,每个项节点有三个域:coef,exp,link分别表示系数,指数,和指向下一节点的指针域。这个整个多项式就可以看做是一个链表了,同时我们也定义了一个多项式类Polynominal,定了了相应的函数来实现加法和乘法操作。

线性表的基本操作Java 线性表的基本操作有_链表

线性表的基本操作Java 线性表的基本操作有_链表_02

#include<iostream>
using namespace std;
class Term
{
public:
    Term(int c,int e);
    Term(int c,int e,Term *nxt);
    Term *InsertAfter(int c,int e);
private:
    int coef;
    int exp;
    Term *link;
    friend ostream &operator<<(ostream &,const Term &);
    friend class Polynominal;
};
Term::Term(int c,int e):coef(c),exp(e)
{
    link=0;
}
Term::Term(int c,int e,Term *nxt):coef(c),exp(e)
{
    link=nxt;
}
Term* Term::InsertAfter(int c,int e)
{
    link=new Term(c,e,link);
    return link;
}
ostream &operator<<(ostream &out,const Term &val)
{
    if(val.coef==0)
        return out;
    out<<val.coef;
    switch(val.exp)
    {
        case 0:break;
        case 1:out<<"X";break;
        default:out<<"X^"<<val.exp;
    }
    return out;
}
class Polynominal
{
public:
    Polynominal();
    ~Polynominal();
    void AddTerms(istream &in);
    void Output(ostream &out)const;
    void PolyAdd(Polynominal& r);
    void PolyMul(Polynominal& r);
private:
    Term *theList;
    friend ostream&operator<<(ostream &,const Polynominal &);
    friend istream &operator>>(istream &,Polynominal &);
    friend Polynominal& operator+(Polynominal &,Polynominal&);
    friend Polynominal & operator * (Polynominal &a, Polynominal &b);
};
Polynominal::Polynominal()
{
    theList=new Term(0,-1);
    theList->link=theList;
}
Polynominal::~Polynominal()
{
    Term *p=theList->link;
    while(p!=theList)
    {
        theList->link=p->link;
        delete p;
        p=theList->link;
    }
    delete theList;
}
void Polynominal::AddTerms(istream &in)
{
    Term *q=theList;
    int c,e;
    for(;;)
    {
        cout<<"input the term(coef,exp):\n";
        cin>>c>>e;
        if(e<0)
            break;
        q=q->InsertAfter(c,e);
    }
}
void Polynominal::Output(ostream &out)const
{
    int first=1;
    Term *p=theList->link;
    cout<<"The polynominal is:\n"<<endl;
    for(;p!=theList;p=p->link)
    {
        if(!first&&(p->coef>0))
            cout<<"+";
        first=0;
        out<<*p;
    }
    cout<<"\n"<<endl;
}
void Polynominal::PolyAdd(Polynominal &r)
{
    Term *q,*q1=theList,*p;
    p=r.theList->link;
    q=q1->link;
    while(p->exp>=0)
    {
        while(p->exp<q->exp)
        {
            q1=q;
            q=q->link;
        }
        if(p->exp==q->exp)
        {
            q->coef=q->coef+p->coef;
            if(q->coef==0)
            {
                q1->link=q->link;
                delete(q);
                q=q1->link;
            }
            else
            {
                q1=q;
                q=q->link;
            }
        }
        else
            q1=q1->InsertAfter(p->coef,p->exp);
        p=p->link;
    }
}
void Polynominal::PolyMul(Polynominal& r)
{
    Polynominal result;             //定义相乘后的数据
    Term *n = result.theList;       //n指向result的头结点
    n = n->InsertAfter(0, 0);       //在result的头结点后插入新结点,系数指数均为0
    Term *p = r.theList->link;      //p指向第一个要处理的结点
    while(p->exp >= 0)              //对r的单循环链表遍历
    {
        Polynominal tmp;            //存储某段相乘后的数据
        Term *m = tmp.theList;      //m指向tmp的头结点
        Term *q = theList->link;    //q指向表头结点的后继结点
        while(q->exp >= 0)          //对当前对象的单循环环链表遍历
        {
            m = m->InsertAfter((p->coef)*(q->coef), (p->exp) + (q->exp)); //生成新结点插入n后
            q = q->link;
        }
        result.PolyAdd(tmp);        //将temp加到result上
        p = p->link;
    }
    Term *q = theList->link;        //q指向表头结点的后继结点
    while(q != NULL)                //删除原对象的所有数据
    {
        theList->link = q->link;
        delete q;
        q = theList->link;
    }
    q = theList;
    q = q->InsertAfter(0, 0);
    PolyAdd(result);                //将result加到当前对象上
}


ostream&operator<<(ostream &out,const Polynominal &x)
{
    x.Output(out);
    return out;
}
istream &operator>>(istream &in,Polynominal &x)
{
    x.AddTerms(in);
    return in;
}
Polynominal &operator+(Polynominal &a,Polynominal&b)
{
    a.PolyAdd(b);
    return a;
}
Polynominal & operator * (Polynominal &a, Polynominal &b)
{
    a.PolyMul(b);
    return a;
}

int  main()
{
    Polynominal p,q;
    cin>>p;
    cout<<p;
    cin>>q;
    cout<<q;
    q=q+p;
    cout<<q;
    q=p*q;
    cout<<q;
    return 0;
}

View Code

运行结果如图:

线性表的基本操作Java 线性表的基本操作有_List_12