三种链表
单链表基本操作(带头结点)
代码可见单向链表
转载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
- 双向循环链表:①让头结点的前驱指针指向链表的最后一个结点 ②让最后一个结点的后继节点指向头结点
- 双向链表的有些操作(如ListLength,GetElem等),仅涉及一个指针;而插入、删除时需要同时修改两个方向上的指针,时间复杂度均为O(n)
基本操作
插入ListInsert(&L, i, e)
在位置i之前插入元素e