线性表
携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第3天,点击查看活动详情
单链表上基本操作实现
- 采用头插法建立单链表
LinkList List_HeadInsert(LinkList &L{//逆向建立单链表
LNode*s;
int x;
L=(LinkList)malloc(sizeof(LNode));//创建头结点
L->next=NULL;//初始为空链表
scanf("$d",&x);//输入结点的值
while(x!=9999){//输入9999表示结束
s=(LNode*)malloc(sizeof(LNode));//创建新结点
s->data=x;
s->next=L->next;
L->next=s;//将新结点插入表中,L为头指针scanf("%d",&x);
}
return L;
}
这里需要注意的是malloc函数,一些知识需要在c语言书学习,大概意思就是分配一片空间出来。 采用头插法建立单链表时,读入数据的顺序与生成的链表中的元素的顺序是相反的。每个结点插入的时间为O(1),设单链表长为n,则总时间复杂度为O(n)。
-
采用尾插法建立单链表 跟头插法类思,不再赘述
-
按序号查找和a安置查找上一届学习过了,这里也不写了。
-
这里要注意的是删除节点操作需要free,看下面的代码
-
p=GetElem(L,i-1);//查找删除位置的前驱结点 q=p->next;//令g指向被删除结点p->next=g->next;//将*g结点从链中“断开” free(g);//释放结点的存储空间
双链表
双链表结点中有两个指针prior和next,分别指向其前驱结点和后继结点。
双链表中结点类型的描述如下:
typedef struct DNode{//定义双链表结点类型
Elemrype data;//数据域
struct DNode *prior,*next;
}DNode, *DLinklist;
双链表在单链表的结点中增加了一个指向其前驱的prior指针,因此双链表中的按值查找和按位查找的操作与单链表的相同。但双链表在插入和删除操做的实现上,与单链表有着大的不同。
双链表的插入操作
s->next=p->next;//将结点*s插入到结点*p之后
p->next->prior=s;
s->prior=p;
p->next=s;
//第一二两部必须在第4部之前
双链表的删除操作
p->next=g->next;
q->next->prior=p;
free(g);//释放结点空间
顺序表和链表的比较
1.存取(读写)方式 顺序表可以顺序存取,也可以随机存取,链表只能从表头顺序存取元素。例如在第i个位置上执行存或取的操作,顺序表仅需一次访问,而链表则需从表头开始依次访问i次。 2.逻辑结构与物理结构 采用顺序存储时,逻辑上相邻的元素,对应的物理存储位置也相邻。而采用链式存储时,逻辑上相邻的元素,物理存储位置不一定相邻,对应的逻辑关系是通过指针链接来表示的。 3.查找、插入和删除操作 对于按值查找,顺序表无序时,两者的时间复杂度均为O(n);顺序表有序时,可采用折半查找,此时的时间复杂度为O(log2n)。 对于按序号查找,顺序表支持随机访问,时间复杂度仅为O(1),而链表的平均时间复杂度为O(n)。顺序表的插入、删除操作,平均需要移动半个表长的元素。链表的插入、删除操作,只需修改相关结点的指针域即可。由于链表的每个结点都带有指针域,故而存储密度不够大。 4.空间分配 顺序存储在静态存储分配情形下,一旦存储空间装满就不能扩充,若再加入新元素,则会出现内存溢出,因此需要预先分配足够大的存储空间。预先分配过大,可能会导致顺序表后部大量闲置;预先分配过小,又会造成溢出。动态存储分配虽然存储空间可以扩充,但需要移动大量元素,导致操作效率降低,而且若内存中没有更大块的连续存储空间,则会导致分配失败。链式存储的结点空间只在需要时申请分配,只要内存有空间就可以分配,操作灵活、高效。
应用题
已知两个链表A和B分别表示两个集合,其元素递增排列。编制函数,求A与B的交集,并存放于A链表中。
算法思想
采用归并的思想,设置两个工作指针pa和pb,对两个链表进行归并扫描,只有同时出现在两集合中的元素才链接到结果表中且仅保留一个,其他的结点全部释放。当一个链表遍历完毕后,释放另一个表中剩下的全部结点。
LinkList Union(LinkList &la,LinkList &lb){
pa=la->next;//设工作指针分别为pa和pb pb=lb->next;
pc=la;//结果表中当前合并结点的前驱指针
while(pa&&pb){
if(pa->data==pb->data){//交集并入结果表中
pc->next=pa;//A中结点链接到结果表
pc=pa;
pa=pa->next;
u=pb;//B中结点释放
pb=pb->next;
free(u);
}
else if(pa->data<pb->data){//若A中当前结点值小于B中当前结点值
u=pa;
pa-pa->next;//后移指针
free(u);//释放A中当前结点
}
else{//若B中当前结点值小于A中当前结点值
u=pb;
pb=pb->next;//后移指针
free(u);/释放B中当前结点
}
}//while结束
while(pa){//B已遍历完,A未完
u=pa;
pa=pa->next;
free(u);
while(pb){
u=pb;
pb=pb->next;
free(u);
}
pc->next=NULL;//置结果链表尾指针为NULL
free(lb);//释放B表的头结点
return la;
}
时间复杂度为o(1).