单链表:先回顾单链表的特点 逻辑相邻 物理上不一定相连
首先初始化单链表,其中主要保存的是该节点自身的值以及下个节点的地址。
有效节点结构体设计:
struct Node{
int data;//数据域
struct Node* next;//指针域
}
以下是单链表的插入以及删除操作:
(一)插入操作
单链表的插入主要分为头插,尾插,以及按位置插入这三种来进行操作。
(1)头插
bool Insert_head(PNode pn, int val)
{
assert(pn!=NULL);//判断不为空
//1.申请新节点
struct Node* pnewnode = (struct Node*)malloc(1 * sizeof(struct Node));
assert(pnewnode != NULL);
pnewnode->data = val;
pnewnode->next = NULL; // 这里可写可不写
//2.找到合适的插入
//头插时插入在头结点的后边,所以不用找
//3.插入
pnewnode->next = p->next;//先让C指向B (不能先断开AB中间的线 不然找不到B)
p->next = pnewnode;//此时再让A指向C
return true;
}
(2)尾插
bool Inseret_tail(PNode pn, int val)
{
//1.申请新节点
struct Node* pnewnode = (struct Node*)malloc(1 * sizeof(struct Node));
assert(pnewnode != NULL);
pnewnode->data = val;
pnewnode->next = NULL; // 这些步骤都与前面的一样
//2.找到合适的插入位置(尾插,需要一个临时指针p指向尾结点)
struct Node* p = pn;
for (p; p->next != NULL; p = p->next);
//3.插入
pnewnode->next = p->next;
p->next = pnewnode;
return true;
}
(3)按位置插入(将C插入到AB)
bool Inseret_pos(PNode pn, int pos, int val)
{
assert(pos >= 0 && pos <= Get_length(pn));
//1.申请新节点
struct Node* pnewnode = (struct Node*)malloc(1 * sizeof(struct Node));
assert(pnewnode != NULL);//确保申请成功
pnewnode->data = val;//传入val
pnewnode->next = NULL; //
//2.找到合适的插入位置(按位置插入AB之间,在这里发现规律,pos等于几则让指向头结点的指针p向后走pos步,此时p指向AB的A)
struct Node* p = pn;
for (int i = 0; i < pos; i++)
{
p = p->next;
}
//3.插入
pnewnode->next = p->next;//先让C指向B (不能先断开AB中间的线 不然找不到B)
p->next = pnewnode;//此时再让A指向C
return true;
}
按位置插入这里改变pos的值便可以实现头插和尾插。
(二)删除操作
(1)头删
bool Del_head(PNode pn)
{
//assert
if (IsEmpty(pn))
{
return false;
}
struct Node* p = pn->next;//pn是头结点 pn->next则是第一个有效节点地址 即头删的节点 则此时p指向待删除节点
//将待删除节点跨越指向(让带删除节点上家的next域指向下家的地址,而下家的地址在待删节点p的next中)
pn->next = p->next;
free(p);
p = NULL;
return true;
}
(2)尾删
bool Del_tail(PNode pn)
{
//assert
if (IsEmpty(pn))
{
return false;
}
//找到待删除节点用p指向(尾删的待删除节点就是倒数第一个节点)
struct Node* p = pn;
for (p; p->next != NULL; p = p->next);//当P指向的next域为空停下来
//q指向倒数第二个节点
struct Node* q = pn;
for (q; q->next != p; q = q->next);
q->next = pn;//q->next = p->next;
free(p);
return true;
}
(3)按位置删 同样这里改变pos的值能实现头删和尾删
bool Del_pos(PNode pn, int pos)
{
//assert
assert(pos >= 0 && pos < Get_length(pn));
if (IsEmpty(pn))//注意这里的判空操作在后面有定义
{
return false;
}
//先找到待删除节点的上一个节点,用q指向 规律:pos等于几 q就向后走几步
struct Node* q = pn;
for (int i = 0; i < pos; i++)
{
q = q->next;
}
//此时 q指向待删除节点的上一个节点
//接下来 再让p指向待删除节点 待删除节点在q的next中
struct Node* p = q->next;
//跨越指向,再释放
q->next = p->next;
free(p);//删除待删除节点
return true;
}
bool IsEmpty(PNode pn)
{
return pn->next == NULL;
}
(4)按值删
bool Del_val(PNode pn, int val)
{
//assert
if (IsEmpty(pn))
{
return false;
}
struct Node* p = Search(pn, val);//判断value是否存在
if (p == NULL)//search返回的地址为空代表没找到
{
return false;
}
//此时待删除节点存在, 且用指针p指向
struct Node* q = pn;
for (q; q->next != p; q = q->next);
//再申请一个临时指针q 让q指向p的上一个节点
q->next = p->next;
free(p);
//跨越指向,和释放
return true;
}
//查找
struct Node* Search(PNode pn, int val)
{
//assert
for (struct Node* p = pn->next; p != NULL; p = p->next)
{
if (p->data == val)
{
return p; //找到 则扔出去
}
}
return NULL; //没找到,返回NULL地址
}
以上便是一些单链表的相关操作,简单可直接拿去使用。