7、群体类和群体数据的组织-2.线性群体

1、线性群体的概念

线性群体中的元素次序与其位置关系是对应的。在线性群体中,又可按照访问元素的不同方法分为直接访问、顺序访问和索引访问。

 对可直接访问的线性群体,我们可以直接访问群体中的任何一个元素,而不必首先访问该元素之前的元素。

对顺序访问的线性群体,只能按元素的排列顺序从头开始依次访问各个元素。

还有两种特殊的线性群体--栈和队列。

2、直接访问群体---数组类

针对静态数组的缺陷,我们来设计一个动态数组类模板Array,它由任意多个位置连续的,类型相同的元素组成,其元素个数可在程序运行是改变。

a、数组类

数组类模板Aarray的声明和实现都在shuzu.h文件中,程序清单如下:

#ifndef ARRAY_CLASS #define ARRAY_CLASS

#include<iostream>

#include<cstdlib>

using namespace std;

#ifndef NULL

const int NULL=0;

#endif    //NULL

//错误类型集合,共有三种类型的错误:数组大小错误、内存分配错误和下标越界 e

num ErrorType {  invalidArraySize,memoryAllocationError,indexOutOfRange };

//错误信息

char *errorMsg[] = {  "Invalid array size", "Memory allocation error", "Invalid index:" };

//数组类模板声明

template <class T>

class Array {

private:  T* alist; //T类型指针,用于存放动态分配的数组内存首地址

 int size;//数组大小  

void Error(ErrorType error, int badIndex = 0)const;//错误处理函数

public:  Array(int sz = 50);    //构造函数  

Array(const Array<T>& A);//拷贝构造函数

 ~Array(void);//析构函数

 Array<T>& operator=(const Array<T>& rhs);//重载“=”使数组对象可以整体赋值  

T& operator[](int i);//重载"[]",使Array对象可以起到C++普通数组的作用  

operator T* (void)const;//重载T*,使Array对象可以起到C++普通数组的作用  

int ListSize(void) const;//取数组的大小  

void Resize(int sz);//修改数组的大小

};

//以下为类成员函数的定义

//模板函数Error实现输出错误信息的功能

template <class T>

void Array<T>::Error(ErrorType error, int badIndex)const

{  cout << errorMsg[error];//根据错误类型,输出相应的错误信息

 if (error == indexOutOfRange)   

cout << badIndex;//如果是下标越界错误,输出错误的下标  

cout << endl;  exit(1); }

//构造函数

template <class T> Array<T>::Array(int sz)

{  if (sz <= 0)   //sz为数组大小  

 Error(invalidArraySize);  

size = sz;

 alist = new T[size];//动态分配size个T类型的元素空间  

if (alist == NULL)

//如果分配内存不成功,输出错误信息  

 Error(memoryAllocationError); };

//析构函数

template <class T> Array<T>::~Array(void)

{  delete[] alist; }

//拷贝构造函数

template <class T> Array<T>::Array(const Array<T>& X)

{  //从对象X取得数组大小,并赋值给当前对象的成员

 int n = X.size;

 size = n;  //为对象申请内存并进行出错检查  

alist = new T[n];//动态分配n个T类型的元素空间

 if (alist == NULL)//如果分配内存不成功,输出错误信息

 {   Error(memoryAllocationError);  }  //从对象X复制数组元素到本对象  

T* srcptr = X.alist;//x.alist是对象X的数组首地址

 T* destptr = alist;//alist是本对象中的数组首地址

 while (n--)   *destptr++ = *srcptr++;

} //重载"="运算符,将对象rhs赋值给本对象。实现对象的整体赋值

template<class T> Array<T>& Array<T>::operator=(const Array<T>& rhs)

{  int n = rhs.size;//取rhs的数组大小  //如果本对象中数组大小与rhs不同,则删除数组原有内存,然后重新分配

 if (size != n)

 {   delete[] alist;//删除数组原有内存  

 alist = new T[n];//重新分配n个元素的内存  

 if (alist == NULL)//如果分配内存不成功,输出错误信息   

 Error(memoryAllocationError);  

 size = n;//记录本对象的数组大小  

}  

//从rhs向本对象复制元素  

T* destptr = alist;  

T* srcptr = rhs.alist;

 while (n--)   

*destptr++ = *srcptr++;

 return *this;//返回当前对象的引用

}

//重载下标运算符,实现与普通数组一样通过下标访问元素,并且具有越界检查功能

template<class T> T& Array<T>::operator[](int n)

{

 if (n<0 || n>size - 1)//检查下标是否越界   

Error(indexOutOfRange,n);  

return alist[n];//返回下标为n的数组元素

}

//重载指针转换运算符,将Array类的对象名转换为T类型的指针,指向当前对象中的私有数组,

//因而可以像使用普通数组首地址一样使用Array类的对象名

template <class T> Array<T>::operator T *(void) const

{  return alist;//返回当前对象中私有数组的首地址 }

//取当前数组的大小

template<class T> int Array<T>::ListSize(void)const {  return size; }

//将数组大小修改为sz

template <class T> void Array<T>::Resize(int sz)

{  if (sz <= 0)  //检查是否sz<=0   

Error(invalidArraySize);

 if (sz == size)  //如果指定的大小与原有大小一样,什么也不做  

 return;  

T* newlist = new T[sz];//申请新的数组内存  

if (newlist == NULL) //测试申请内存是否申请成功   

Error(memoryAllocationError);

 int n = (sz <= size) ? sz : size;//将sz与size中较小的一个赋值给n  //将原有数组中前n个元素复制到新数组中  

T* srcptr = alist;//原数组alist的首地址  

T* destptr = newlist;//新数组newlist的首地址  

while (n--)  //复制数组元素  

{   *destptr++ = *srcptr++;  }  

delete[] alist;//删除原数组  

alist = newlist;//使alist指向新数组  

size = sz;//更新sz } #endif//ARRAY_CLASS

 zhishu.cpp

#include<iostream>

#include<iomanip>

#include"shuzu.h"

using namespace std;

int main()

{  

Array<int> A(0);  //用来存放质数的数组,出师状态有10个元素

 int n;  

int primecount = 0, i, j;

 cout << "Enter a value>=2 as upper limit for prime numbers:";  

cin >> n;

 A[primecount++] = 2;//2是一个质数

 for (i = 3; i < n; i++)  {   

//如果质数表满了,便再申请分配10个元素的空间  

 if (primecount == A.ListSize())  

 {    A.Resize(primecount + 10);   }   

//大于2的偶数不是质数,因此略过本次循环的后继部分,进入下一次循环  

 if (i % 2 == 0)    

continue;   

//检查3,5,7,...,i/2是否i的因子  

 j = 3;  

 while (j <= i / 2 && i%j != 0)  

  j += 2;   //若上述参数均不为i的因子,则i为质数   

if (j>i / 2)    

A[primecount++] = i;  

}  

for (i = 0; i < primecount; i++)//输出质数

 {   

cout << setw(5) << A[i];  

 if ((i + 1) % 10 == 0)//每输出10个数换行一次   

 cout << endl;  

}  

cout << endl;

 getchar();  

getchar();

}

原文地址:https://www.cnblogs.com/gary-guo/p/6286493.html