这就要好好数落一下顺序表,由于顺序表在做插入或者删除操作的时候,需要移动大量的元素,而单链表不要求逻辑上相邻的元素在物理位置上也相邻,故没有顺序存储结构所具有的弱点,但也失去了顺序表可 随机存取 的优点。
如上图所示,为一个单链表结点的基本结构:数据域(存储数据)+指针域(直接后继存储位置)废话不多说,接下来上代码。
typedef struct LNode{
ElemType data; //数据域
struct LNode *next; //指针域
}LNode, *LinkList; //*LinkList 指向结构体的指针类型变量
在这里为大家介绍两种方法:1.头插法(课本P31)、2.尾插法,后续为了方便操作,在算法上用了尾插法。
讲解:这里的L被称为头指针,他的数据域没有数据,他的直接后继指向链表中的第一个元素,画上图的主要目的就是解释一下源码中的
p->next = L->next; L->next = p; 也可以拿笔划一划,电脑上画太累了。
void CreateList(LinkList &L, int n){
L = (LinkList) malloc (sizeof(LNode));
//建立头结点
L->next = NULL;
//输入数据
for(int i=n;i>0;i--){
//创建新的节点
LinkList p = (LinkList) malloc (sizeof(LNode));
scanf("%d",&p->data);
p->next = L->next;
L->next = p;
}
}
配套头插法打印算法: 此时有头结点,调用的时候要注意
//由于是头插法嵌入数据,所以第一个数据在最后一位
void Headprintf(LinkList L){
if(L->next != NULL){
Headprintf(L->next);
}
//头节点没有数据
printf("%d ",L->data);
}
自己动手画一遍,印象更深刻。
讲解: 在顺序执行算法时,可以发现,这里的end相当于一个打工仔。
void EndCreateList(LinkList &L, int n){
L = (LinkList) malloc (sizeof(LNode));
//建立头结点
L->next = NULL;
//建立临时尾节点
LinkList end = L;
//输入数据
for(int i=n;i>0;i--){
//创建新的节点
LinkList p = (LinkList) malloc (sizeof(LNode));
scanf("%d",&p->data);
end->next = p;
end = p;
}
end->next = NULL;
}
尾插法打印算法:
//尾插法打印内容
void Endprintf(LinkList L, int n){
printf("单链表的元素内容--->");
//头节点没有数据
for(int i=0;i<n;i++){
printf("%d ",L->data);
L = L->next;
}
printf("\n");
}
//当第i个元素存在时,其赋值给e并返回OK,否则返回ERROR
Status GetElem(LinkList L, int i, ElemType &e){
LinkList p = L->next;
int j = 0;
while(p && j<i){
p = p->next;
j++;
}
if(!p || j>i){
return ERROR;
}
e = p->data;
return OK;
}
//在带头节点的单链表L中第i个位置之前插入元素e
Status ListInsert(LinkList &L, int i, ElemType e, int &length){
LinkList p = L;
int j = 0;
while(p && j<i-1){
p = p->next;
j++;
}
if(!p || j>i-1){
return ERROR;
}
LinkList s = (LinkList) malloc (sizeof(LNode));
s->data = e;
s->next = p->next;
p->next = s;
length++;
return OK;
}
//在带头结点的单链表L中,删除第i个元素,并由e返回其值
Status ListDelete(LinkList &L, int i, ElemType &e, int &length){
LinkList p = L;
int j = 0;
while(p->next && j<i-1){
p = p->next;
j++;
}
if(!(p->next) || j>i-1){
return ERROR;
}
LinkList q = p->next;
p->next = q->next;
e = q->data;
length--;
return OK;
}
//合并非递减的单链表
void MergeList(LinkList &La, LinkList &Lb, LinkList &Lc){
//不算头结点
LinkList pa = La->next;
LinkList pb = Lb->next;
LinkList pc;
Lc = pc = La; //用La的头结点作为Lc的头结点
while(pa && pb){
if(pa->data <= pb->data){
pc->next = pa;
pc = pa;
pa = pa->next;
}else{
pc->next = pb;
pc = pb;
pb = pb->next;
}
}
//插入剩余段
pc->next = pa ? pa : pb;
}
注:这里是张某人自己测试用的。
main(){
int na,nb;
LinkList La,Lb,Lc;
printf("链表a的长度");
scanf("%d",&na);
printf("请输入链表a内容");
EndCreateList(La, na);
printf("链表b的长度");
scanf("%d",&nb);
printf("请输入链表b内容");
EndCreateList(Lb, nb);
//合并
MergeList(La, Lb, Lc);
//打印
int lengthc = na+nb;
Endprintf(Lc->next, lengthc);
// //插入
// ListInsert(L, 2, 10, n);
// Endprintf(L->next, n);
// //删除
// int e;
// ListDelete(L, 2, e, n);
// printf("删除的元素为%d\n",e);
// Endprintf(L->next, n);
// int e;
// int index = 2;
// int status = GetElem(L, index, e);
// if(status == ERROR){
// printf("第%d位数字不存在\n",index);
// }else{
// printf("%d\n",e);
// }
//打印的时候不打印头结点的数据域
//Endprintf(L->next, n);
}