浅谈线性表的基本操作与应用

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

一,线性表的基本操作

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

#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

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

#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

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

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

#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

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

#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;
}

二,线性表的应用

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

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

#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;
}

运行结果如图:

时间: 2024-10-11 16:26:44

浅谈线性表的基本操作与应用的相关文章

Problem O: 线性表的基本操作

#include <iostream> #include <iomanip> #include <map> #include <string> #include <list> using namespace std; class MyList { public : list<int> elements; int len; int curLen; MyList(int _len):len(_len){} void append(int

顺序存储的线性表的基本操作

刚开始学数据结构,几乎算是什么都不会,想记录一下学习的东西,所以就学别人开始写博客. 刚学了顺序存储的线性表的基本操作,把操作写了一遍.可能会有错误. 顺序存储的线性表,用结构体类型.注意:结构体并不是用来存储元素的,elem才是存储元素的首地址 1 typedef struct 2 { 3 ElemType *elem;//存储空间基地址 6 int length;//表长 7 int listsize;//表容量 8 }SqList; 初始化:构造空表L,返回一个状态,需要带回一个表给基地址

数据结构:线性表的基本操作

顺序表学习:参考<大话数据结构> 涉及到顺序表的基本操作有如下: int initList(SqList *L);  /** 初始化操作,建立一个空的线性表 **/int printList(SqList L);    /** 打印线性表中的每一个元素 **/int getlength(SqList L);  /** 返回线性表元素的个数 **/int createList(SqList *L,int length);  /** 创建一个链表长度为length的线性表 **/int inser

Problem C: 线性表的基本操作

Description 线性表是一类重要的且基础的数据结构.请定义MyList类,来模拟针对线性表的插入.删除等操作: 1. 数据成员int *elements:线性表元素. 2. 数据成员int len:线性表容量,即线性表的最大长度. 3. 数据成员int curLen:线性表的当前容量,即当前拥有的元素个数. 4. 构造函数MyList(int _len):构造最大容量为_len的线性表. 5. void append(int d):在线性表的末尾追加元素d. 6. void insert

线性表的基本操作

#include<stdio.h>#include<stdlib.h>typedef struct {    int *elem;    int length;    int listsize;}SqList; #define LIST_MAX 10#define LIST_ADD 2 int InitList(SqList *L){    L->elem=(int*)malloc(LIST_MAX*sizeof(int));    if(!L->elem)    { 

浅谈Oracle表之间各种连接

Oracle表之间的连接分为三种: 1.内连接(自然连接) 2.外连接 2.1.左外连接(左边的表不加限制,查询出全部满足条件的结果) 2.2.右外连接(右边的表不加限制,查询出全部满足条件的结果) 2.3.全外连接(左右两边表均不加限制) 3.自连接(同一张表内的连接) SQL的标准写法: select table1.column,table2.column from table1 [inner|left|right|full] join table2 on table1.column1 =

浅谈线性素数筛

素数筛的用处还是蛮多的,有很多和素数有关的题都要用到素数筛,所以有一个高效的筛法自然是非常好的吖,普通筛法(暴力筛法)就不说了,因为有了高效的也没人在会用普通筛法了吧. 线性素数筛是用每一个合数的最小的质因数筛掉它,所以时间复杂度保证是线性的. 模板:https://www.luogu.org/problemnew/show/P3383 代码: 1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 int

浅谈线性基

几个概念或引理 概念1:数集的异或和:定义一个无符号整数集合S(注意,我们接下来讨论的集合均指由无符号整数为元素构成的集合),则S的异或和就是S中所有元素互相异或的结果. 概念2:张成:子集Ti ⊆  S且子集Ti异或和组成的集合K就是数集S的张成,记做K=span(S)就可以理解为S中取任意多个元素异或运算获得的值组成的集合就是S的张成K. 概念3:线性相关和线性无关: 线性相关: 设元素x∈S,数集去除元素x后的数集为S’,且满足x∈span(S’)即 span(S)=span(S’),就可

浅谈数据结构之线性表顺序存储(一)

 首先,数据结构是由某一数据元素集合及该集合中所有数据元素之间的关系组成.具体来说,数据结构应当包含三方面的内容:(1).数据的逻辑结构:(2).数据的存储结构:(3).对数据所施加的操作.而数据的存储结构形式有两种:顺序存储与链式存储.在这里,先谈一谈线性表的顺序存储. 线性表:零个或多个数据元素的有限序列.第一,它是一个序列,也就是说,元素之间是有顺序的:第二,它是有限的,即元素个数是有限的.而线性表的顺序存储结构,说白了,就是在内存中找块地,通过占位的形式把一定的内存空间给占了,然后把相同