1.逻辑结构
线性表是n个类型相同的数据元素的有限序列,除第一个元素外,每个数据元素只有一个直接前驱和直接后继,数据元素之间具有一对一的关系,一个线性表中的数据类型必须属于同一数据对象
2.顺序存储
用一组地址连续的存储单元依次存储线性表中的各个元素
2.1地址计算
Loc(ai)=Loc(a1)+(i-1)*k(每个元素占k个单元,Loc(a1)为首元素地址)
2.2顺序存储的表示
2.2.1代码
#define MAXSIZE 100 //宏定义表示线性表的最大长度
typedef struct
{
ElemType elem[MAXSIZE]; //线性表占用的数组空间
int last; //记录线性表中最后一个元素在数组中的位置,空表置为-1
}SeqList;
ElemType是为了描述统一而自定的,可以根据需要为int,char,float,或者struct类型
通过变量定义语句SeqList L;将L定义为SeqList类型的变量,可通过L.elem[i-1]访问顺序表中序号为i的元素
通过指针变量定义语句SeqList L1,*L; L=&L1;将L定义为指向SepList类型的指针变量,使用时可以通过L->elem[i-1]访问顺序表中序号为i的元素
2.2.2基本运算
1.查找操作
查找顺序表中与给定值e相等的数据元素,并返回其序号
int Locate(SeqList L,ElemType e)
{int i=0;
while(i<=L.last&&L.elem[i]!=e) //顺序扫描表,直到找到或者到了表尾依旧没找到
i++;
if(i<=last)
return i+1;
else
return -1 //表明查找失败
}
2.插入操作
在表的第i个元素前插入一个新的元素
算法思想:先判断插入位置是否合理,在判断表是否满了,允不允许插入,最后找到位置插入并且将表尾向后移一位
#define OK 1
#define ERROR 0
int InsList(Seqlist *L,int i,ElemType e)
{
int k;
if(i<1||i>L->last+2){
printf("插入位置不合法")
return ERROR;
}
if(L->last>=MAXSIZE-1){
printf("表已满,无法插入");
return ERROR;
}
for(k=L->last;k>=i-1;k--)
L->elem[k+1]=L->elem[k];
L->elem[i-1]=e;
L->last++;
return OK;
}
3.删除操作
将表中的第i个元素删除,并将删除的元素储存起来
int DelList(SeqList *L,ElemType *e)
{
int k;
if(i<1||i>L->last+1){
printf("删除位置不合理");
return ERROR;
}
*e=L->elem[i-1];
for(k=i;k<=l->last;k++)
L->elem[k-1]=L->elem[k];
L->last--;
return OK;
}
4.合并操作
有两个顺序表LA和LB,其元素均为非递减有序排列。编写算法,将他们合并成一个顺序表LC,要求LC也是非递减有序排列。
void mergeList(SeqList *LA,SeqList *LB,SeqList *LC)
{
int i,j,k,l;
i=0;j=0;k=0;
while(i<=LA->last&&j<=LB->last){
if(LA->elem[i]<=LB->elem[j]){
LC->elem[k]=LA->elem[i];
i++;k++;
}
else{
LC->elem[k]=LB->elem[j];
j++;k++;
}
while(i<=LA->last) //看是否有表空,直接接到C表后面去
{
LC->elem[k]=LA->elem[i];
i++;k++
}
while(j<=LB->last)
{
LC->elem[k]=LB->elem[j];
j++;k++
}
LC->last=LA->last+LB->last+1;
}
3.链式存储
3.1单链表
用一组任意的存储单元来存放线性表的结点,可以是连续的也可以是不连续的。链表的结点包括两个域:数据域用来存储节点的值,指针域用来储存数据元素的直接后继的地址,每个结点只有一个next指针域的链表称为单链表
为了操作的统一方便,可以在单链表的第一个结点之前附设一个头节点。头节点的数据域可以储存一些关于线性表的长度等附加信息,也可以不储存任何信息。
typedef struct Node
{
ElemType data;
struct Node* next;
}Node,*LinkList;
LinkList与Node*同为结构指针类型,这两种类型是等价的。通常习惯上用LinkList定义指向某个单链表的头指针变量,例如定义LinkList L,则L为指向单链表的头指针变量;用Node*定义指向单链表中结点的指针,例如Node* p,则p为指向单链表中结点的指针变量。
3.1.1单链表的基本运算
1.初始化单链表
InitList(LinkList *L)
{
*L=(LinkList)malloc(sizeof(Node));
(*L)->next=NULL;
}
2.头插法建立单链表
void CreatFromHead(LinkList L)
{Node *s;
char c;
int flag=1; //flag初值为1,当输入'$'时flag为0,建表结束
while(flag){
c=getchar();
if(c!='$')
{
s=(Node *)malloc(sizeof(Node)); //建立新结点
s->data=c;
s->next=L->next; //将s结点插入表头
L->next=s;
}
else flag=0;
}
}
采用头插法得到的单链表输入顺序与逻辑顺序相反
3.尾插法建立单链表
添加一个尾指针,使其指向表尾,此时输入顺序与逻辑顺序相同
void CreatFromTail(LinkList L)
{
Node *r,*s;
int flag=1;
r=L;
char c;
while(flag){
c=getchar();
if(c!='$'){
s=(Node*)malloc(sizeof(Node));
s->data=c;
r->next=s;
r=s;
}
else{
flag=0;r->next=NULL; //将最后一个结点的next域置为空,表示结束建表
}
}
}
4.单链表插入操作
在线性表的第i个结点位置之前插入一个新元素e
5.单链表的删除操作
步骤与插入操作大同小异
6.合并两个有序的单链表
有两个单链表LA,LB,其元素均为非递减有序排列,编写一个算法,将他们合并成一个单链表LC,且LC也是非递减有序排列
LinkList MergeLinkList(LinkList LA,LinkList LB)
{
Node *pa,*pb,*r;
LinkList LC;
pa=LA->next;pb=LB->next;
LC=LA;
LC->next=NULL;r=LC;
while(pa!=NULL&&pb!=NULL){
if(pa->data<=pb->data){
r->next=pa;r=pa;pa=pa->next;
}
else{
r->next=pb;r=pb;pb=pb->next;
}
}
if(pa) r->next=pa; //表A没完就接到c后面
if(pb) r->next=pb;
return LC;
}
3.2循环链表
循环链表是一个首尾相接的链表,与单链表在判别p结点是否为尾结点时条件不同,单链表中判别条件为p!=NULL或p->next!=NULL,而单循环链表的判别条件则是p!=L或p->next!=L
3.2.1循环链表的基本运算
1.初始化循环链表
InitCLinkList (LinkList *CL){
*CL=(LinkList)malloc(sizeof(Node));
(*CL)->next=*CL;
}
2.建立循环链表
本质上与建立单链表无异,只是在最后一步要让最后一个结点的next域指向头结点
3.合并两个循环链表
分为两种情况,如果给的是表头指针,则要遍历链表到表尾,再将其中一个链表的表尾指针连接到表头,并将另一个链表释放掉,如果给的是表尾指针则不需要遍历操作
3.3双向链表
结构定义如下
typedef sruct DNode
{
ElemType data;
struct DNode *prior,*next;
}DNode,*DoubleList;
优点是可以从表中快速找到一个结点的直接前驱,与单链表类似,它也可以存在双向循环链表
3.3.1双向链表的插入操作
int DLinkList(DoubleList L,int i,ElemType e){
DNode *s,*p;
s=(DNode *)malloc(sizeof(DNode));
/*先检查插入位置是否合理,此处代码省略,如果合理,则找到第i个结点,并让p指向它*/
if(s){
s->data=e;
s->prior=p->prior; //1
p->prior->next=s; //2
s->next=p; //3
p->prior=s; //4
return TRUE; //TRUE和FALSE是宏定义了的
}
else return FALSE;
}
3.2.2双向链表的删除操作
1.p->prior->next=p->next 2.p->next->prior=p->prior free(p)