文章目录
- 2.3插入
- 2.3.1按位序插入
- 2.3.2指定结点后插入
- 2.3.3指定结点前插入
- 2.4删除
- 2.4.1按位序删除
- 2.4.2指定结点删除
- 2.5查找
- 2.5.1按位查找
- 2.5.2按值查找
2.3插入
2.3.1按位序插入
ListInsert(&L,i,e):插入操作。在表L中的第i个位置上插入指定元素e。
- 带头结点
把头结点看作第0个结点,位置 i 就是 i-1 个结点
//在第i个位置插插入元素e(带头结点)
bool ListInsert(LinkList &L, int i, ElemType e){
if(i<1) //位序1是头结点
return false;
LNode *p; //指针p指向当前扫描到的结点
int j=0; //当前p指向的是第几个结点
p = L; //L指向头结点,头结点是第0个结点(不存数据)
//循环找到第 i-1 个結点,p是前一个结点,插入p的后面
while (p!=NULL && j<i-1) {
p=p->next;
j++;
}
if(p==NULL) //i值不合法
return false;
LNode *s = (LNode *)malloc(sizeof(LNode));//新结点
s->data = e;
s->next = p->next;
p->next = s; //将结点s连到p之后
return true; //插入成功
}
有一个while所以时间复杂度是O(n)
- 不带头结点
bool ListInsert(LinkList &L, int i, ElemType e){
if(i<1)
return false;
if(i==1){ //插入第1个结点的操作与其他结点操作不同
LNode *s = (LNode *) malloc(sizeof(LNode));
s->data = e;
s->next = L;
L=s; //头指针指向新结点
return true;
}
LNode *p; //指针p指向当前扫描到的结点
int j=1; //当前p指向的是第几个结点
p=L; //p指向第1个结点(注意:不是头结点)
//循环找到第 i-1 个結点,p是前一个结点,插入p的后面
while (p!=NULL && j<i-1) {
p=p->next;
j++;
}
if(p==NULL) //i值不合法
return false;
LNode *s = (LNode *) malloc(sizeof(LNode));
s->data = e;
s->next = p->next;
p->next = s;
return true;//插入成功
}
2.3.2指定结点后插入
InsertNextNode(LNode *p, ElemType e)
//后插操作:在p结点之后插入元素e
bool InsertNextNode(LNode *p, ElemType e){
if (p==NULL)
return false;
LNode *s = (LNode *)malloc(sizeof(LNode));
if (s==NULL) //内存分配失败
return false;
s->data = e; //用结点s保存数据元素e
s->next = p->next;
p->next = s; //将结点s连到p之后
return true;
}
时间复杂度O(1)
2.3.3指定结点前插入
InsertPriorNode(LNode *p, ElemType e)
//前插操作:在p结点之前插入元素e
bool InsertPriorNode(LNode *p, ElemType e){
if (p==NULL)
return false;
LNode *s = (LNode *)malloc(sizeof(LNode));
if (s==NULL) //内存分配失败
return false;
//
s->next = p->next;
p->next = s; //新结点s连到p之后
s->data = p->data; //将p中元素复制到s中
p->data = e; //p中元素覆盖为e
return true;
}
转移p结点的内容到后面,在逻辑上实现在p结点前插入。
时间复杂度O(1)
前插操作:在p结点之前插入结点 s(王道书版本)
//前插操作:在p结点之前插入结点s
bool InsertPriorNode(LNode *p, LNode *s){
if (p==NULL || s==NULL)
return false;
s->next = p->next;
p->next = s; //s连到p之后
//交换数据域部分
ElemType temp = p->data;
p->data = s->data;
s->data = temp;
return true;
}
2.4删除
2.4.1按位序删除
ListDelete(&L,i,&e):删除操作。删除表L中第i个位置的元素,并用e返回删除元素的值。
//按位序删除(带头结点)
bool ListDelete(LinkList &L,int i,ElemType e){
if(i<1)B
return false;
LNode *p; //指针p指向当前扫描到的结点
int j = 0; //当前p指向的是第几个结点
p = L; //L指向头结点,头结点是第0个结点(不存数据)
//循环找到第 i-1 个结点
while(p!=NULL && j<i-1){
p=p->next;
j++;
}
if(p==NULL) //i值不合法
return false;
LNode *q = p->next; //令q指向被删除结点(拿到结点),也就是p->next
e = q->data; //用e返回元素的值
p->next = q->next; //将*q结点从链中“断开”
free(q); //释放结点的存储空间
return true; //删除成功
}
例图:
时间复杂度:O(n)
2.4.2指定结点删除
DeleteNode(LNode * p)
//删除指定结点p
bool DeleteNode(LNode * p)
{
if (p == NULL) //若删除的节点为空结点,操作无效
return false;
LNode *q = p->next; //定义一个q指针,令q指向*p的后继结点
p->data = p->next->data;//和后继结点交换数据域,相当于将p节点的后一个结点的数据赋值到p结点中
p->next = q->next; //将*q结点从链中“断开”
free(q); //释放后继结点的存储空间
return true;
}
时间复杂度:O(1)
由于需删除结点的前驱结点未知,或者要删除的是第一个结点,且不带头结点。那么换个思路,创建一个q指针指向p结点的后继结点,将p结点的后继结点q中的数据覆盖到p结点数据域中,然后令p结点指向q结点的后继结点: p->next = q->next;
再删掉“悬空”的q结点完成操作。
等同于:1->2->3->4,若要删掉1,可以先令前两个数据交换,2->1->3->4,再让1的指针链断开,令2指向3: 2->(1)-3->4, 把1断开,于是就是2->3->4。
注意:如果要删除的p结点是最后一个结点,以上偷天换日法无法使用,我们只能从表头开始依次往后寻找p的前驱,时间复杂度为O(n)。
2.5查找
2.5.1按位查找
GetElem(L,i):按位查找操作。获取表L中第i个位置的元素的值。
单链表按位查找是指根据节点在链表中的位置(即节点序号或下标)来查找节点的操作。通常情况下,我们需要查找的节点序号是从1开始计数的,即第1个节点、第2个节点、第3个节点等。基本思路是从链表头节点开始,遍历链表,直到找到第k个节点,或者链表遍历结束。如果链表遍历结束仍未找到第k个节点,则返回空指针。
//按位查找
LNode* GetElem(LinkList L, int i)
{
if(i < 0) //判断i是否合法
return NULL;
LNode *p; //指针p指向当前扫描到的结点
int j=0; //当前p指向的是第几个结点
p=L; //L指向头结点,头结点是第0个结点(不存数据)
while(p!=NULL && j<i){ //寻找第i个结点
p=p->next; //让p指针依次往后移
j++;
}
return p;
}
王道书版:
LNode* GetElem(LinkList L, int i){
int j=1;
LNode *p=L->next;
if(i==0) //特殊情况是头结点
return L;
if(i<1) //小于1的结点不合法
return NULL;
while(p!=NULL && j<i){
p=p->next;
j++;
}
return p;
}
时间复杂度:O(n)
2.5.2按值查找
LocateElem(L,e):按值查找操作。在表L中查找具有给定关键字值的元素。
- 单链表查找需要遍历整个链表,时间复杂度为 O(n),其中 n 是链表节点的个数。
- 当链表为空时,需要特别处理。
- 如果目标值在链表中不存在,可能需要额外处理,比如返回一个空指针,或者打印出 “Not Found” 等提示信息。
- 需要根据具体问题和代码实现,特别注意链表头节点指针的正确性,以及节点指针的移动和连接等操作。
//按值查找, 找到数据域 ==e 的结点
LNode* LocateElem(LinkList L, ElemType e) {
LNode *p = L->next;
//从第1个结点开始查找数据域为e的结点
while(p != NULL && p->data != e)
p = p->next;
return p; //找到后返回该结点指针,否则返回NULL
}
时间复杂度为:O(n)