第二章线性表
线性表的逻辑结构
线性表是由n(n≥)个数据元素组成的有限序列当n=是称为空表非空的线性表记为(aaa…an)
线性表的基本运算有
)InitList(L)构造空表即表的初始化;
)ListLength(L)求表的结点个数即表长;
)GetNode(Li)取表中第i个结点要求≤i≤ListLength(L);
)LocateNode(Lx)查找L中值为x的结点并返回结点在L中的位置有多个x则返回首个没有则返回特殊值表示查找失败
)InsertList(Lxi)在表的第i个位置插入值为x的新结点要求≤i≤ListLength(L)+;
)DeleteList(Li)删除表的第i个位置的结点要求≤i≤ListLength(L);
线性表的顺序存储结构
顺序表
顺序表是把线性表的结点按逻辑次序存放在一组地址连续的存储单元里
结点的存储地址计算公式Loc(ai)=Loc(a)+(i)*C;≤i≤n
顺序表的定义
#define listsize
typedef int datatype;
typedef struct{
datatype data[listsize];
int length;
]seqlist;
顺序表山的基本运算
插入
void insertlist(seqlist *Ldatatype xint i)
{
int j;
if(i<||i>L>length+)
error(position error);
if(L>length>=listsize)
error(overflow);
for(j=L>length;j>=i;j)
L>data[j+]=L>data[j];
L>data[i]=x;
L>length++;
}
在顺序表上插入要移动表的n/结点算法的平均时间复杂度为O(n)
删除
void delete (seqlist *Lint i)
{
int j;
if(i<||i>L>length)
error(position error);
for(j=i;j<=L>length;j++)
L>data[j]=L>data[j];
L>length;
}
在顺序表上删除要移动表的(n+)/结点算法的平均时间复杂度为O(n)
线性表的链式存储结构
用链接方式存储的线性表称链表
单链表
在结点中除了存储结点值还存储结点的后继结点的地址data|nextdata是数据域next是指针域只有一个链域的链表称单链表
单链表结点的定义
Typedef char datatype;
Typedef struct node{
Datatype data;
Struct node *next;
}listnode;
typedef listnode *linklist;
listnode *p;
linklist head;
结点的动态生成p=(listnode *)malloc(sizeof(listnode));结点的回收free(p);
建立单链表时间复杂度为O(n)
) 头插法建表
Link createlistF(void)
{
char ch;
linklist head;
listnode *s;
head=NULL;
ch=getchar();
while(ch!=\n){
s=(listnode *)malloc(sizeof(listnode));
s>data=ch;
s>next=head;
head=s;
ch=getchar();
}
return head;
}
)尾插法建表
Link createlistR(void)
{
char ch;
linklist head;
listnode *s *r;
s=NULL;r=NULL;
while((ch=getchar())!=\n){
s=(listnode *)malloc(sizeof(listnode));
s>data=ch;
if(head=NULL)
head=s;
else
r>next=s;
r=s;
}
if(r!=NNULL)
r>next=NULL;
return head;
}
在链表开始结点前附加一个头结点的优点是)链表第一个位置的操作无需特殊处理;)将空表和非空表的处理统一
)带头结点的尾插法建表
Linklist createlisR(void)
{
char ch;
linklist head=(listnode *)malloc(sizeof(listnode));
listnode *s *r;
r=head;
while((ch=getchar())!=\n){
s=(listnode *)malloc(sizeof(listnode));
s>data=ch;
r>next=s;
r=s;
}
r>next=NULL;
return head;
}
查找运算时间复杂度为O(n)
) 按序号查找
Listnode * getnode(linklist headint i)
{
int j;
listnode *p;
p=head;j=;
while(p>next&&j
p=p->next;
j++;
}
if(i==j)
return p;
else
return NULL;
}
2) 按值查找。Tw.wINgwiT.cOm
Listnode * locatenode(linklist head ,datatype key)
{
listnode *p=head->next;
while(p&&p->data!=key)
p=p->next;
return p;
}
3. 插入运算。时间复杂度为O(n)。
Void insertlist(linklist head ,datatype x, int i)
{
listnode *p;
p=getnode(head,i-1);
if(p==NULL);
error(“position error”);
s=(listnode *)malloc(sizeof(listnode));
s->data=x;
s->next=p->next;
p->next=s;
}
4. 删除运算。时间复杂度为O(n)。
Void deletelist(linklist head ,int i)
{
listnode *p ,*r;
p=getnode(head ,i-1);
if(p==NULL||p->next==NULL)
error(“position error”);
r=p->next;
p->next=r->next;
free(r);
}
2.3.2循环链表。
循环链表是一种首尾相连的链表。特点是无需增加存储量,仅对表的链接方式修改使表的处理灵活方便。
单链表是将终端结点的指针域指向表头结点或开始结点。为使空表和非空表处理一致可设置一个头结点。
用头指针表示的单循环链表查找开始结点的时间是O(1),查找尾结点的时间是O(n);用尾指针表示的单循环链表查找开始结点和尾结点的时间都是O(1)。
2.3.3双链表
在结点中增加一个指针域,prior|data|next。形成的链表中有两条不同方向的链称为双链表。
双链表结点定义。
Typedef struct dlistnode{
Datatype data;
Struct dlistnode *prior,*next;
}dlistnode;
typedef dlistnode *dlinklist;
dlinklist head;
1) 双链表的前插操作。时间复杂度为O(1)。
Void dinsertbefore(dlistnode *p ,datatype x)
{
dlistnode *s=malloc(sizeof(dlistnode));
s->data=x;
s->prior=p->prior;
s->next=p;
p->prior->next=s;
p->prior=s;
}
2) 双链表的删除操作。时间复杂度为O(1)。
Void ddeletenode(dlistnode *p)
{
p->prior->next=p->next;
p->next->prior=p->prior;
free(p);
}
2.4顺序表和链表的比较。
1) 基于空间的考虑:顺序表的存储空间是静态分配的,链表的存储空间是动态分配的。顺序表的存储密度比链表大。因此,在线性表长度变化不大,易于事先确定时,宜采用顺序表作为存储结构。
2) 基于时间的考虑:顺序表是随机存取结构,若线性表的操作主要是查找,很少有插入、删除操作时,宜用顺序表结构。对频繁进行插入、删除操作的线性表宜采用链表。若操作主要发生在表的首尾时采用尾指针表示的单循环链表。
附二:
第二章 线性表
*************************************************************************************
线性表是由n≥0个数据元素组成的有限序列。n=0是空表;非空表,只能有一个开始结点,有且只能有一个终端结点。
*************************************************************************************
线性表上定义的基本运算:·构造空表:Initlist(L)
·求表长:Listlength(L)
·取结点:GetNode(L,i)
·查找:LocateNode(L,x)
·插入:InsertList(L,x,i)
·删除:Delete(L,i)
*************************************************************************************