线性顺序表

线性表:

简介:

线性表是最基本、最简单、也是最常用的一种数据结构。

线性表中数据元素之间的关系是一对一的关系,即除了第一个和最后一个数据元素之外,其它数据元素都是首尾相接的(注意,这句话只适用大部分线性表,而不是全部。比如,循环链表逻辑层次上也是一种线性表(存储层次上属于链式存储),但是把最后一个数据元素的尾指针指向了首位结点)。

我们说“线性”和“非线性”,只在逻辑层次上讨论,而不考虑存储层次,所以双向链表和循环链表依旧是线性表。

在数据结构逻辑层次上细分,线性表可分为一般线性表和受限线性表。一般线性表也就是我们通常所说的“线性表”,可以自由的删除或添加结点。受限线性表主要包括栈和队列,受限表示对结点的操作受限制。

线性表的逻辑结构简单,便于实现和操作。因此,线性表这种数据结构在实际应用中是广泛采用的一种数据结构。

定义:

线性表(linear list)是数据结构的一种,一个线性表是n个具有相同特性的数据元素的有限序列。数据元素是一个抽象的符号,其具体含义在不同的情况下一般不同。

在稍复杂的线性表中,一个数据元素可由多个数据项(item)组成,此种情况下常把数据元素称为记录(record),含有大量记录的线性表又称文件(file)

线性表中的个数n定义为线性表的长度,n=0时称为空表。在非空表中每个数据元素都有一个确定的位置,如用ai表示数据元素,则i称为数据元素ai在线性表中的位序。

线性表的相邻元素之间存在着序偶关系。如用(a1,…,ai-1,ai,ai+1,…,an)表示一个顺序表,则表中ai-1领先于ai,ai领先于ai+1,称ai-1是ai的直接前驱元素,ai+1是ai的直接后继元素。当i=1,2,…,n-1时,ai有且仅有一个直接后继,当i=2,3,…,n时,ai有且仅有一个直接前驱。

特征:

  1. 集合中必存在唯一的一个“第一元素”。
  2. 集合中必存在唯一的一个 “最后元素” 。
  3. 除最后一个元素之外,均有 唯一的后继(后件)。
  4. 除第一个元素之外,均有 唯一的前驱(前件)。

基本操作:

  1. MakeEmpty(L) 这是一个将L变为空表的方法

  2. Length(L) 返回表L的长度,即表中元素个数

  3. Get(L,i) 这是一个函数,函数值为L中位置i处的元素(1≤i≤n)

  4. Prior(L,i) 取i的前驱元素

  5. Next(L,i) 取i的后继元素

  6. Locate(L,x) 这是一个函数,函数值为元素x在L中的位置

  7. Insert(L,i,x)在表L的位置i处插入元素x,将原占据位置i的元素及后面的元素都向后推一个位置

  8. Delete(L,p) 从表L中删除位置p处的元素

  9. IsEmpty(L) 如果表L为空表(长度为0)则返回true,否则返回false

  10. Clear(L)清除所有元素

  11. Init(L)同第一个,初始化线性表为空

  12. Traverse(L)遍历输出所有元素

  13. Find(L,x)查找并返回元素

  14. Update(L,x)修改元素

  15. Sort(L)对所有元素重新按给定的条件排序

  16. strstr(string1,string2)用于字符数组的求string1中出现string2的首地址

顺序表的定义:

顺序表是在计算机内存中以数组的形式保存的线性表,是指用一组地址连续的存储单元依次存储数据元素的线性结构。线性表采用顺序存储的方式存储就称之为顺序表。顺序表是将表中的结点依次存放在计算机内存中一组地址连续的存储单元中。

将表中元素一个接一个的存入一组连续的存储单元中,这种存储结构顺序结构

顺序表的表示与实现:

base.h:

这个头文件主要用来存放公用的常量和类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//base.h
//-----公用的常量和类型----------
#include<iostream>
#include<stdlib.h>
#include<time.h>
using namespace std;
#include<malloc.h>
#include<string.h>

//函数结果状态代码
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1 //不可行的 infeaslble
#define OVERFLOW -2

typedef int Status;
typedef int ElemType;

sqList.h:

aqList.h头文件用来具体实体实现各函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
//sqList.h
//线性表存储空间的初始化分配量,为100
#define LIST_INIT_SIZE 100
//线性表存储空间的分配增量 10
#define LISTINCREMENT 10

typedef struct{
ElemType * elem; //存放空间基址
int length; //当前长度
int listsize; //当前分配的存储容量
}SqList;

//构造一个空的线性表
Status InitList_Sq(SqList &L){
//构造一个空的线性表L
L.elem = (ElemType *)malloc(LIST_INIT_SIZE * sizeof(ElemType));
if(!L.elem) exit(OVERFLOW); //如果存储分配失败,退出
L.length = 0; //空白长度为0
L.listsize = LIST_INIT_SIZE; //初始存储容量
return OK;
}//InitList_Sq

//销毁列表L
Status DestroyList(SqList &L){
if(L.elem){
free(L.elem);
L.elem = NULL;
cout<<"线性表销毁成功!"<<endl;
return OK;
}else{
cout<<"线性表不存在,不需要销毁!"<<endl;
return ERROR;
}
}//DestroyList

//初始条件:线性表L已存在
//操作结果:将L置为空表
Status ClearList_Sq(SqList &L){
L.length = 0;
cout<<"线性表清空成功!"<<endl;
return OK;
}//ClearList_Sq

//初始条件:线性表L已存在
//操作结果:若为空表返回TRUE,不为空返回FALSE
Status ListIsEmpty_Sq(SqList L){
if(L.length == 0) //如果列表长度为0,返回TRUE
return TRUE;
else //否则返回FALSE
return FALSE;

}// ListIsEmpty_Sq

//初始条件:线性表L已存在
//操作结果:返回线性表中元素的个数
Status ListLength_Sq(SqList L){
return L.length;
}//ListLength

//初始条件:线性表L已存在
//操作结果:获得列表第i个值
Status GetElem_Sq(SqList L, int i, ElemType &e){
if(L.length == 0 || i < 1 || i > L.length)
return ERROR;
e = L.elem[i-1];
return OK;
}//GetElem_Sq

//初始条件:线性表L已存在
//操作:查找其中某个值,返回L中第一个与e相等的数据元素的位序
// 若没找到返回0
Status LocateElem_Sq(SqList L, ElemType e){
int i = 1;
ElemType *p = L.elem;
while(i <= L.length && *p++ != e)
++i;
if(i < L.length)
return i;
else
return 0;
}//LocateElem_Sq

//初始条件:线性表L已存在
//操作:获得前驱
Status PriorElem_Sq(SqList L, ElemType cur_e, ElemType pre_e){
int i=0;
while(i < L.length && !(L.elem[i] == cur_e))
++i;
if(i == 0 || i == L.length){
cout<<cur_e<<"没有前驱!"<<endl;
return ERROR;
}else{
pre_e = L.elem[i-1];
cout<<cur_e<<"的前驱是:"<<pre_e<<endl;
return OK;
}
}//PriorElem_Sq

//初始条件:线性表L已存在
//操作:求后继
Status NextElem_Sq(SqList L, ElemType cur_e, ElemType next_e){
int i=0;
while(i < L.length && !(L.elem[i] == cur_e))
++i;
if(i >= L.length - 1){
cout<<cur_e<<"没有后继!"<<endl;
return ERROR;
}else{
next_e = L.elem[i+1];
cout<<cur_e<<"的后继是:"<<next_e<<endl;
return OK;
}
}//NextElem_Sq

//初始条件:线性表L已存在
//操作,插入一个元素
Status ListInsert_Sq(SqList &L, int i, ElemType e){
//在顺序线性表L中第i个位置之前插入新的元素e
//i的合法值为 1<= i <=ListLength_Sq(L) + 1;
if(i < 1 || i > L.length+1)
return ERROR; //如果i的值不合法,返回错误
if(L.length >= L.listsize){
ElemType *newbase;
newbase = (ElemType *)realloc(L.elem, (L.listsize + LISTINCREMENT) * sizeof(ElemType));
if(!newbase) //如果空间分配失败,返回溢出
return OVERFLOW;
L.elem = newbase; //把分配的新地址给列表
L.listsize += LISTINCREMENT; //增加存储容量
}
ElemType *q, *p;
q = &(L.elem[i-1]); //q为插入的位置
for(p = &(L.elem[L.length - 1]); p >= q; --p)
*(p + 1) = *p; //插入位置之后的元素右移
*q = e; //插入e
++L.length; //列表长度加1
return OK;
}//ListInsert_Sq

//初始条件:线性表L已存在
//操作:删除某个元素
Status ListDelete_Sq(SqList &L, int i, ElemType &e){
//在顺序线性表中删除第i个元素,并用e返回其值
//i的合法值为 1<= i <= L.length_Sq(L)
if(i < 1 || i > L.length) return ERROR;
ElemType *p = &(L.elem[i-1]);//p为删除元素的位置
e = *p; //被删除元素的值赋给e
ElemType *q = L.elem + L.length - 1; //q为列表尾元素地址
for(++p; p <= q; ++p)
*(p-1) = *p; //被删除元素之后的位置左移
--L.length; //表常减1
return OK;
}//ListDelete_Sq

//初始条件:线性表L已存在
//操作:修改表中元素
Status Update_Sq(SqList L, ElemType cur_e, ElemType new_e){
if(LocateElem_Sq(L,cur_e) != 0)
{
L.elem[LocateElem_Sq(L,cur_e)-1] = new_e;
cout<<"元素更新成功!"<<endl;
return OK;
}else{
cout<<"本列表中没有 "<<cur_e<<"元素,无法更新数据!"<<endl;
return ERROR;
}
}//Update_Sq

//遍历列表
Status ListTraverse(SqList &L){
if(L.length == 0)
cout<<"列表为空表!"<<endl;
else{
for(int i = 1; i <= L.length; i++){
if(i == L.length) //如果为最后一个数,最后输出换行符
cout<<L.elem[i-1]<<endl;
else
cout<<L.elem[i-1]<<" , ";
}
}
return OK;
}//LisetTraverse

main.cpp:

用来测试上面的函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include "base.h"
#include "sqList.h"

int main(){
SqList L;
int i;
ElemType e;
InitList_Sq(L); //初始化线性表
cout<<"遍历表:";
ListTraverse(L); //遍历表
//给表赋值
for(i = 0; i < 10; i++)
ListInsert_Sq(L,1,i);
cout<<"列表是否为空:"<<ListIsEmpty_Sq(L)<<endl;
cout<<"在给列表赋值十个值后的遍历表:";
ListTraverse(L); //遍历表
cout<<"列表的长度是:"<<ListLength_Sq(L)<<endl;
ListInsert_Sq(L,5,500); //在第五个位置插入500
cout<<"第五个位置插入500后的遍历表:";
ListTraverse(L);
ListDelete_Sq(L,5,e);
cout<<"删除操作,删除的数是:"<<e<<endl;
cout<<"删除第五个位置的元素后的遍历表:";
ListTraverse(L);
GetElem_Sq(L,5,e);
cout<<"获取第五个位置的数:"<<e<<endl;
cout<<"与1相等的是第:"<<LocateElem_Sq(L,1)<<"位"<<endl;
cout<<"把8改为3操作:";
Update_Sq(L,8,3);
cout<<"更新元素后的遍历表:";
ListTraverse(L);
PriorElem_Sq(L,5,e);
PriorElem_Sq(L,9,e);
NextElem_Sq(L,5,e);
NextElem_Sq(L,0,e);
cout<<"清空线性表:";
ClearList_Sq(L);
cout<<"列表是否为空:"<<ListIsEmpty_Sq(L)<<endl;
DestroyList(L); //第一次销毁线性表
DestroyList(L);//第二次销毁线性表

return 0;
}

主方法测试结果:

测试结果

图:程序测试结果

坚持原创技术分享,您的支持将鼓励我继续创作!