线性表 —— 三种链表

单链表基本操作(带头结点)

代码可见单向链表
转载https://blog.csdn.net/qq_42518941/article/details/113704044

IntiList L(LinkList &L);
ListEmpty(LinkList L);

//注意:参数为L
//判断链表是否为空 == 判断头指针指针域是否为空;参数不带&的意思是因为不想对链表操作

DestroyList(LinkList &L);

//单链表的删除,思路:p = L; L = L->next; free( p);

ClearList(LinkList &L); 对比DestroyList

//清空单链表,思路:依次释放所有结点(除头结点),并将头结点指针域为空,p = L->next;(q = p->next; free p;p = q;)直到p == NULL;**有q的原因是因为头结点必须存在!!!**最终L->next = NULL;
总结:①从头结点开始操作,p = L;②从首元结点开始操作,p = L->next;

ListLength(LinkList L)

//参数为L,因为不想对链表操作
//求链表的表长,思路:从首元结点开始,依次计数所有的结点。对首元结点开始→p = L->next;(i++;p = p->next;)

GetElem(LinkList L, int i, ElemType &e);

//取单链表中第i个元素的内容,

p = L->next;
j = 1;
while (p && j<i) {
	p = p->next;
	j++;
}
if (!p || j > i) return ERROR; //可将i为非正数,p提前空这三种情况包含在内
/*操作*/
LocateElem(L,e)

//查找①该数据的地址;②该数据的位置:没有找到该元素,返回空,时间复杂度O(n)
①查找地址

p = L->next;
j = 1;
while (p && p->data != e)
	p = p->next;
return p; //若是找到了,直接返回地址;若是找不到,代表p的值为NULL,直接返回即可

②查找位置

p = L->next;
j = 1;
while (p && p->data != e) {
	p = p->next;j++;
}
if (p) return j;
else return 0;
LinkInsert(&L, i, e)

/对比LinkDelete的循环条件,理由:在第i个元素之前插入一个数据元素,i的合理取值为1~n+1,因此和删除节点的循环条件并不相同,时间复杂度O(n)

p = L; //从头结点开始的原因是,可能在首元结点之前插入
j = 0;  //j!=1的原因是从头结点开始操作
s = (Lnode * )malloc(sizeof(Lnode));
s.data = e;
while (p && j < i-1) { 
	p = p->next;
	j++;
}
if (!p && j > i-1) return ERROR; //i大于表长+1或者i<1,插入非法
s-> next = p->next; 
p->next = s;
return OK;
ListDelete(&L, i, e);

对比LinkInsert的循环条件:理由:删除第i个结点 ,i合理取值为1~n,因此和循环条件的删除并不相同,时间复杂度O(n)

p = L; //因为可能删除首元结点
j = 0; //从头结点开始删除
while (p->next && j < i-1){
	p = p->next;
	j++;
}
if (!(p->next) && j > i-1) return ERROR;
q = p->next;
p->next = q->next;
e = q->data;
free(q);
头插法

元素插在链表的头部,也叫前插法,时间复杂度O(n)
在这里插入图片描述
p = (LNode*)malloc(sizeof(LNode));p->data = an;p->next = L->next; L->next = p;
p = (LNode*)malloc(sizeof(LNode));p->data = a(n-1);p->next = L->next; L->next = p;…共执行n次

尾插法

元素插在链表尾部,也叫后插法,有头指针和尾指针®,时间复杂度为O(n)
在这里插入图片描述
p = (LNode*)malloc(sizeof(LNode));p->data = an(从1~n);p->next = NULL; r->next = p; r = p

循环链表

首尾相接的链表,尾结点的指针域指向头结点,整个链表形成一个环
优点:从表中任意结点出发均可找到表中的其他结点

头指针表示链表

初始化头指针时,它的指针域并不等于NULL,而是指向它本身在这里插入图片描述
由于循环链表中没有NULL指针,进行遍历操作时,终止条件为它们是否等于头指针
头指针表示循环链表①找a1的复杂度O(1) ②找an的复杂度为O(n),不方便,因为表的操作通常是在首尾进行的

尾指针表示循环链表

在这里插入图片描述
①a1的存储位置为R->next->next ②an的存储位置为R
时间复杂度为O(1)

两个带尾指针的循环链表合并

将链表A接在B前面
在这里插入图片描述
p保存Ta头结点,Tb的首元接到Ta尾结点,释放Tb头结点,改变Tb尾结点的指针

双向链表

在单链表的每个结点里再增加一个指向其直接前驱的指针域prior
定义:
typedef struct DuLNode {
ElemType data;
struct DuLNode *prior, *next;
}DuLNode, *DuLinkList
6

  1. 双向循环链表:①让头结点的前驱指针指向链表的最后一个结点 ②让最后一个结点的后继节点指向头结点
    在这里插入图片描述
  2. 双向链表的有些操作(如ListLength,GetElem等),仅涉及一个指针;而插入、删除时需要同时修改两个方向上的指针,时间复杂度均为O(n)
基本操作
插入ListInsert(&L, i, e)

在位置i之前插入元素e
在这里插入图片描述

删除ListDelete(&L, i, &e)

在这里插入图片描述

三种链表的比较

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值