线性表是最常用的一种数据结构,除了第一个和最后一个数据元素,其它数据元素都是首尾相接的。
数据类型
线性表的数据类型定义如下:
- 线性表的数据对象集合为 { a 1 , a 2 , ⋯ , a n } \left \{a_1, \; a_2, \; \cdots, \; a_n \right \} {a1,a2,⋯,an}。
- 每个元素的类型均为
DataType
。 - 除第一个元素 a 1 a_1 a1外,每一个元素有且只有一个直接前驱元素。
- 除了最后一个元素 a n a_n an外,每一个元素有且只有一个直接后继元素。
基本操作
线性表的基本操作如下:
InitList(*L)
:初始化操作,建立一个空的线性表。ListEmpty(L)
:若线性表为空,返回True
,否则返回False
。ClearList(*L)
:将线性表清空。GetElem(L, i, *e)
:将线性表L
中的第i
个位置元素值返回给e
。LocateElem(L, e)
:在线性表L
中查找给定值e
相等的元素:
- 若查找成功,则返回该元素在表中的序号。
- 若查找失败,则返回
0
。
ListInsert(*L, i, e)
:在线性表L
中的第i
个位置插入元素e
。ListDelete(*L, i, *e)
:删除线性表L
中第i
个位置元素,并用e
返回其值。ListLength(L)
:返回线性表L
的元素个数。
对于实际问题涉及的关于线性表的更复杂的操作,完全可以用这些基本操作的组合来实现。
假设La
表示集合A
,Lb
表示集合B
,现在要得到一个集合A
,使得
A
=
A
∪
B
A = A \cup B
A=A∪B:
void unionL ( SqList *La, SqList Lb ) {
int La_len, Lb_len, i;
ElemType e;
La_len = ListLength ( *La );
Lb_len = ListLength ( Lb );
for ( i = 1; i <= Lb_len; i++ ) {
GetElem ( Lb, i, &e );
if ( !LocateElem ( *La, e ) ) {
ListInsert ( La, ++La_len, e );
}
}
}
初始化
定义一个线性表,并使用一些随机数进行初始化:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAXSIZE 20
typedef int ElemType;
typedef struct { /* 线性表的顺序存储结构 */
ElemType data[MAXSIZE]; /* 数组,用于存储数据元素,长度为MAXSIZE */
int length; /* 线性表当前长度 */
} SqList;
SqList Init() { /* 顺序表的初始化 */
SqList L; /* 定义一个顺序表 */
L.length = 0; /* 顺序表的长度为0 */
return L; /* 返回空顺序表 */
}
SqList Create ( SqList L ) { /* 顺序表的建立 */
int i;
srand ( ( unsigned ) time ( NULL ) );
for ( i = 0; i < 10; i++ ) {
L.data[i] = rand() % 100;
L.length++;
}
return L;
}
int main() {
SqList nmList;
nmList = Init();
nmList = Create ( nmList );
int i;
for ( i = 0; i < nmList.length; i++ ) {
printf ( "%d ", nmList.data[i] );
}
printf ( "\n" );
}
查找
查找线性表是最基本的操作之一:
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
typedef int Status;
/* 初始条件:顺序线性表L已存在,1 ≤ i ≤ ListLength(L) */
/* 操作结果:用e返回L中第i个数据元素的值 */
Status GetElem ( SqList L, int i, ElemType *e ) {
if ( L.length == 0 || i < 1 || i > L.length ) {
return ERROR;
}
*e = L.data[i - 1];
return OK;
}
插入
插入元素的步骤如下:
- 如果插入的位置不合理,那么就抛出异常。
- 如果线性表长度大于等于数组长度,则抛出异常或者动态增加容量。
- 从最后一个元素开始向前遍历到第
i
个位置,分别将它们都向后移动一个位置。 - 将要插入的元素填入位置
i
处。 - 表长加
1
。
/* 初始条件:顺序线性表L已存在,1≤ i ≤ ListLength(L) */
/* 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1 */
Status ListInsert ( SqList *L, int i, ElemType e ) {
int k;
if ( L->length == MAXSIZE ) { /* 顺序线性表已经满 */
return ERROR;
}
if ( i < 1 || i > L->length + 1 ) { /* 当i比第一位置小,或者比最后一位置后一位置还要大时 */
return ERROR;
}
if ( i <= L->length ) { /* 若插入数据位置不在表尾 */
for ( k = L->length - 1; k >= i - 1; k-- ) { /* 把要插入位置之后的数据元素向后移动一位 */
L->data[k + 1] = L->data[k];
}
}
L->data[i - 1] = e; /* 将新元素插入 */
L->length++;
return OK;
}
删除
删除元素的步骤如下:
- 如果删除位置不合理,抛出异常。
- 取出要删除的元素。
- 从删除元素位置开始遍历到最后一个元素位置,分别将它们向前移动一个位置。
- 表长减
1
。
/* 初始条件:顺序线性表L已存在,1 ≤ i ≤ ListLength(L) */
/* 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1 */
Status ListDelete ( SqList *L, int i, ElemType *e ) {
int k;
if ( L->length == 0 ) { /* 线性表为空 */
return ERROR;
}
if ( i < 1 || i > L->length ) { /* 删除位置不正确 */
return ERROR;
}
*e = L->data[i - 1];
if ( i < L->length ) { /* 如果删除不是最后位置 */
for ( k = i; k < L->length; k++ ) { /* 将删除位置后继元素前移 */
L->data[k - 1] = L->data[k];
}
}
L->length--;
return OK;
}