计算机考研之数据结构-线性表
数据结构-线性表
抽象描述
定义
- 元素为单个的数据元素
- 元素个数有限
- 元素数据类型相同
- 有逻辑上的先后关系
- 每个元素有且仅有一个直接前驱
- 除最后一个元素以外,每个元素有且仅有一个直接后继
操作
InitList(&L)
,构造一个空的线性表。
Length(L)
,返回线性表长度。
LocateElem(L,e)
,根据值查找元素。
GetElem(L,i)
,根据索引查找元素。
ListInsert(&L,i,e)
,在指定索引处插入元素。
ListDelete(&L,i,&e)
,删除指定索引处的元素,并使用引用返回删除元素的值。
PrintList(L)
,顺序输出线性表索引的元素。
Empty(L)
,判断线性表是否为空。
DestroyList
,销毁线性表。
顺序表
线性表的顺序存储结构称之为顺序表。
相对于链表,顺序表最重要的特征是随机访问,即顺序表可以使用O(1)的时间找到指定索引的元素。
定义
静态定义:
#define MAX 50
typedef struct{
int data[MAX];
int length;
}SqList;
动态定义:
#define InitSize 100
typedef struct{
int *data; //指向动态分配数组的指针
int MAX, length;
}SqList;
L.data = (int*)malloc(sizeof(int)*InitSize) //c的动态分配方式
L.data = new int[InitSize] //c++的动态分配方式
操作
这里分清楚次序与数组下标或者说索引,次序从1开始,数组下标从0开始,我们这里默认i
是索引。MAX
插入,复杂度O(n)。
bool ListInsert(SqList &L, int i, int e){
if(!(i>=0 && i<L.length)) return false;
if(L.length>=MAX) return false;
for(int j=L.length; j>=i+1; j--)
L.data[j] = L.data[j-1];
L.data[i] = e
L.length++;
return true;
}
删除,复杂度O(n)。
bool ListDelete(SqList &L, int i, int &e){
if(!(i>=0 && i<L.length)) return false;
e = L.data[i];
for(int j=i-1, j<L.length-1; j++){
L.data[j-1]=L.data[j];
}
L.length--;
return true;
}
值查找
bool LocateElem(SqList L, int e, int& i)
int j;
for(j=0; i<L.length; i++)
if(L.data[j] == e){
i = j;
return true;
}
return false;
}
单链表
线性表的链式存储结构称之为链表。
定义
typedef struct LNode{
int data;
struct LNode *next;
}LNode, *LinkList;
通常使用头指针来表示一个链表。为了操作上的方便有的时候也会在头指针之前附加一个头结点。
头结点一般不存储数据。
下面的所有操作都是以有头结点为例子的。
操作
-
头插法建立链表
LinkList CreatList(LinkList &L){ LNode *s; int x; L=(LinkList)malloc(sizeof(LNode)); //创建头结点 L->next=NULL; while(scanf("%d", &x)){ s=(LNode*)malloc(sizeof(LNode)); s->data=x; s->next=L->next; L->next=s; } return L; }
-
尾插法
LinkList CreatList(LinkList &L){ LNode *s, *r; int x; // r为指向表尾的指针 L=(LinkList)malloc(sizeof(LNode)); //创建头结点 L->next=NULL; while(scanf("%d", &x)){ s=(LNode*)malloc(sizeof(LNode)); s->data=x; r->next=s; r=s; } r->next=NULL; // 尾结点置空 return L; }
-
序号索引
LNode* GetElem(LinkList L, int i){ if(i<0) return NULL; if(i==0) return L; int j=1; LNode* p=L->next; while(p&&j<i){ p=p->next; j++; } return p; }
-
插入结点
p=GetElem(L, i-1); s->next=p->next; p->next=s;
-
删除结点
p=GetElem(L,i-1); q=p->next; p->next=q->next; free(q);
双链表
定义
typedef struct DNode{
int data;
struct DNode *prior;
struct DNode *next;
}
操作
-
插入,在p后插入一个s节点
s->next=p->next; p->next->prior=s; s->prior=p; p->next=s;
-
删除一个p之后的q节点
p->next=q->next; q->next->prior=p; free(q);
小结
关于顺序表和链表的一些重要的比较:
- 存取方式
- 顺序表可以顺序存储,也可以随机存储,但是链表只能顺序存储。
- 增删查操作
- 链表的单独的增删操作都是O(1),索引查找为O(n)。而顺序表反之,索引查找O(1),增删操作O(n)。
所以,顺序表适合查找场景,链表适合频繁增删的场景。
习题
暂空。