线性表一般分为顺序表和链表,本篇是对顺序表的回顾,以C++创建简单学生健康管理系统为例。
顺序表是线性表基于数组的存储表示。其定义是:将线性表中的所有项,根据其逻辑顺序(有序或无序皆可),依次存储到一片连续的空间里面,空间的开始位置会被指定好(一般实际起始位置在运行时分配)。
1.顺序表节点的结构体定义:
struct student
{
public:
int node;
string name;
string sex;
string birthday;
string health;
};
2.顺序表的类定义:
class seqlist
{
protected:
student *data; //指针的形式
int maxSize; //初始化时顺序表的最大长度
int last; //当前最后一个节点的标号
public:
seqlist(); //构造函数
~seqlist() { delete[] data; } //析构函数
int length() { return last + 1; } const //此处的 const 表示该函数不能修改类的数据成员
void Search(int nodes); //查找表中的某一项
bool insertdata(int i, student& stu); //插入数据(传入引用以实现修改实参)
bool removedata(int i); //删除某一项
void input(); //初始化输入
void readdata(); //从文件中读取
void wridata(); //写入文件
void output(); //输出整个顺序表
};
3.各函数的具体实现
seqlist::seqlist()
{
maxSize = 60;
last = -1;
data = new student[maxSize]; //初始化分配空间
/*datas = new students[maxSize];*/
if (data == NULL)
{
cerr << "存储分配错误!" << endl;
}
}
void seqlist::input()
{
int i = -1;
cout << "--------------请按顺序输入初始学生信息(学号 姓名 性别 生日 健康情况):---------------" << endl;
cout << "--------------------输入学号为任意负数则停止输入,最大数量为60-------------------------" << endl;
do
{
i++;
cin >> data[i].node >> data[i].name >> data[i].sex >> data[i].birthday >> data[i].health;
last = i - 1;
} while ((data[i].node >= 0) && (i <= maxSize - 1));
}
void seqlist::Search(int nodes)
{
int i = 0;
for (i = 0;i <= last;i++)
{
if (data[i].node == nodes)
{
cout << data[i].node << " " << data[i].name << " " << data[i].sex
<< " " << data[i].birthday << " " << data[i].health << endl;
i = i + 1;
}
}
if (i == 0)
{
cout << "查无此人!请检查之后重新输入" << endl;
}
}
bool seqlist::insertdata(int i, student& stu) //插入时先检查当前表的大小,及插入位置的合法性
{
if (last == maxSize - 1) return false;
if (i<0 || i>last + 1) return false;
for (int j = last;j >= i;j--) //插入时要将插入位置之后的全部后退一个位置
{ //注意从last开始
data[j + 1].node = data[j].node;
data[j + 1].name = data[j].name;
data[j + 1].birthday = data[j].birthday;
data[j + 1].sex = data[j].sex;
data[j + 1].health = data[j].health;
}
data[i].node = stu.node;
data[i].name = stu.name;
data[i].birthday = stu.birthday;
data[i].sex = stu.sex;
data[i].health = stu.health;
last++;
return true;
}
bool seqlist::removedata(int i) //同理删除某一项时,先检查
{
if (last == -1)return false;
if (i<1 || i>last + 1) return false;
for (int j = i;j <= last;j++) //删除时直接用删除位置后面的覆盖前面的(实际中应该不能这样)
{ //注意从i开始
data[j - 1].node = data[j].node;
data[j - 1].name = data[j].name;
data[j - 1].birthday = data[j].birthday;
data[j - 1].sex = data[j].sex;
data[j - 1].health = data[j].health;
}
last--;
return true;
}
void seqlist::readdata()
{
student restd;
ifstream file; //文件流
file.open("data.txt", ios::in); //打开
for (int i = 0;i <= last;i++)
{
file >> data[i].node >> data[i].name >> data[i].sex >> data[i].birthday >> data[i].health;
}
file.close();
output();
}
void seqlist::wridata()
{
fstream file;
file.open("data.txt", ios::out);
for (int i = 0;i <= last;i++)
{
file.write((char *)& data[i], sizeof(data[i]));
}
file.close();
}
void seqlist::output()
{
for (int i = 0;i <= last;i++)
{
cout << data[i].node << " " << data[i].name << " " << data[i].sex << " "
<< data[i].birthday << " " << data[i].health << endl;
}
}
4.对顺序表的解析:
(1)已知数据在顺序表中的节点位置时,要得到该数据十分容易,直接用数组下标即可
(2)当不知到数据的位置,进行搜索时,则要对每个节点逐个进行比较,这时平均要比较(n+1)/2个表项
(3)当要插入数据时,需要将插入位置之后的每一项都后移一个位置,整体来说平均要移动n/2个表项
(4)当要删除数据时,与插入同理,改向后移动为向前移动即可,平均移动(n-1)/2个表项
总体来说:顺序表是易查找(已知位置时),难修改的,或者说修改顺序表的时间复杂度较高,它需要一片连续的空间。因此,顺序表不适用于插入或删除频繁的情况,也不适合存储空间需求不定的情况。下一章为链表,与顺序表恰好相对应。