数据结构笔记—2.2线性表的顺序存储结构及实现

顺序表的定义和特点

线性表的存储方式有多种,有基于数组的存储表示、基于链表的存储表示、散列的存储表示,其中顺序表是线性表基于数组的存储表示。
其用一段地址连续的存储单元,依次存储线性表中的数据元素。
顺序表结构
其特点有

  1. 各个表项的逻辑顺序与物理顺序一致。
  2. 对顺序表中的所有表项,可以顺序访问,也可以随机访问。
    线性表存储表示

顺序表的类定义

顺序表可以用C++的一维数组来实现,C++的一维数组是可以静态分配,也可以动态分配的。在传统的C语言中可用静态、动态方式描述顺序表的存储。
为保证程序的灵活性,本例采用动态方式定义顺序表。用C++的描述顺序表的类声明及部分操作如下。在该定义中,利用了数组作为顺序表的存储结构,被封装在类的私有域中。

#include<iostream.h>
#include<stdlib.h>
#include "linerList.h"              //将上节定义的顺序表模板类作为基类并加入头文件
const int defaultsize=100;
template <class T>
class SeqList:public LinearList<T>
{
protected:
    T *data;       //**顺序表存储数组**,“T”类型,根据对象数据类型而变化以实现多态
    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;
        }
    }
    int Insert (int i, T & x);       //插入
    int 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);
};

const成员函数的意义

注意在搜索和定位函数中const起保护作用,表示该成员函数不能改变对象的数据的值。且const成员函数不能调用非const成员函数

顺序表的主要操作实现

SeqList

构造函数

template <class T>	          
 SeqList<T> :: SeqList ( int sz ) {    //传递的参数为表的长度
     if ( sz > 0 ) {
	      MaxSize = sz;  last = -1;			
	      data = new T [MaxSize]; //用new创建动态数组
          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;
    }
}

当程序调用具有SeqList类型返回值的函数时都要使用复制构造函数,用以复制和返回运算结果。如没有定义构造函数,系统会自动建立一个复制构造函数来完成以上工作。

reSize(int newSize)

重定义数组大小

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;//把data指针指向新数组
        maxSize=newSize;//更新长度
    }
}

search ( T & x ) const

template <class T>
int SeqList<T> :: search ( T & x ) const
{
//搜索函数:在顺序表中从头查找结点值等于
//给定值x的结点所在位置,如果没找到返回0
    for(int  i = 0; i <= last ; i++)
        if (data[i]==x)
            return i+1 ;
    return 0;
}

Insert(int i, T& x)

算法描述:

  1. 如果表满了,则抛出上溢异常;
  2. 如果元素的插入位置不合理,则抛出位置异常;
  3. 将最后一个元素至第i个元素分别向后移动一个位置;
  4. 将元素x填入位置i处;
  5. 表长加1;
template <class T>
bool SeqList<T> :: Insert (T& x, int i )//插入的数据,插入的位置
{
    if (last+1 >= MaxSize|| (i < 1 || i > last + 2) )
        return false;
    for (int j = last+1; j >= i; j--)
        data[j] = data[j-1];
    data[i-1] = x;
    last++;
}

删除、输入输出操作

template <class T>
bool SeqList<T> :: Remove ( int i, T& x )
{
//在表中删除已有元素 x
    if(last==-1 ||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;
        if(last<=maxSize-1)
            break;
        cout<<"个数输入有误";
    }
    for(int i=0; i<=last; i++)
    {
        cin>>data[i];
        cout<<i+1<<endl;
    }
}
template <class T>
void SeqList<T> ::output()
{
    cout<<"当前元素最后位置为"<<last<<endl;

    for(int i=0; i<=last; i++)
    {
        cout<<"#"<<i+1<<":"<<data[i]<<endl;
    }
}

顺序表的应用

集合的并交运算

并运算

void Union ( SeqList<int> & A, SeqList<int> & B)
{
    int n = A.Length ( ), x;
    int m = B.Length ( );
    for ( int i = 1; i < =m; i++ )
    {
        B.getData(i,x);         //在B中取一元素
        int k = A.Search (x);     //在A中搜索它
        if ( k == 0 )              //若未找到插入它,将其插入A中
        {
            A.Insert (n, x); 
            n++;
        }
    }
}

交运算

void Intersection ( SeqList<int> & A,
                    SeqList<int> & B )
{
    int n = A.Length ( );
    int m = B.Length ( );
    int i = 1, x;
    while ( i < =n )
    {
        A.get Data(i, x);      //在A中取一元素
        int k = B.search (x);    //在B中搜索它
        if ( k == 0 )
        {
            A.Remove (i,x);
            n- - ;
        }
        //未找到在A中删除它
        else
            i++;
    }
}

顺序表的优缺点

顺序表的优点:

  1. 无需为表示表中元素之间的逻辑关系而增加额外的存储空间;
  2. 随机存取:可以快速地存取表中任一位置的元素。
    顺序表的缺点:
  3. 插入和删除操作需要移动大量元素;
  4. 表的容量难以确定,表的容量难以扩充;
  5. 造成存储空间的碎片。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值