单链表的基本结构单元就是结构体变量,链表的意义在于将结构体通过指针的形式连接起来,即每一个结构体的指针指向下一个结构体
基本元素——结构体
struct Node
{
int data;
struct Node *next;
};
创建表头表示整个链表
//1 创建一个表头表示整个链表
struct Node *createlisthead()
{
//链表的基本结构单元就是结构体变量
//结构体指针指向结构体变量
//1 赋值结构体变量的地址
//2 动态内存申请
struct Node *listhead = (struct Node*)malloc(sizeof(struct Node));
//差异化处理,表头不使用数据
listhead->next = NULL;
return listhead;
}
创建节点
每一次创建节点的时候,把数据传到函数中,创建一个结构体,并把数据储存起来,指针指向空指针
//2 创建节点,为插入做准备
struct Node* createnewnode(int data)
{
struct Node *newnode = (struct Node*)malloc(sizeof(struct Node));
newnode->data = data;
newnode->next = NULL;
return newnode;
}
表头/表尾/特定位置插入
新的节点指向头节点后面的一个节点,头节点指向新的节点
//3 (表头)链表的插入
void insertnodebyhead(struct Node*headnode, int data)
{
struct Node*newnode = createnewnode(data);
newnode->next = headnode->next;
headnode->next = newnode;
}
表尾方式的插入重点在于通过空指针的判断方式找到表尾
//4 表尾插入
void insertnodebytail(struct Node*headnode,int data)
{
struct Node*newnode = createnewnode(data);
//找到表尾
struct Node*tailnode = headnode;
while (tailnode->next != NULL)
{
tailnode = tailnode->next;
}
tailnode->next = newnode;
}
1 通过传入结构体中的数据来找到指定位置
2 期间需要判断判读链表是否为空的情况
3 当找到最后一个节点时依然没有此数据,则表示没有此信息
4 找到后直接通过新节点指向后面的节点,前面的节点指向新节点即可
//5 在特定的位置(前面)插入
void insertnodebyappoint1(struct Node*headnode, int data, int posdata)
{
struct Node*posnodefront = headnode;
struct Node*posnode = headnode->next;
if (posnode == NULL)
{
printf("链表为空");
return;
}
else
{
while (posnode->data != posdata)
{
posnodefront = posnode;
posnode = posnodefront->next;
if (posnode == NULL)
{
printf("未找到相关信息");
return;
}
}
struct Node*newnode = createnewnode(data);
newnode->next = posnode;
posnodefront->next = newnode;
}
}
//5 在特定的位置(后面)插入
void insertnodebyappoint2(struct Node*headnode, int data, int posdata)
{
struct Node*posnode = headnode;
struct Node*posnodeback = headnode->next;
if (posnode == NULL)
{
printf("链表为空");
return;
}
else
{
while (posnode->data != posdata)
{
posnode = posnodeback;
posnodeback = posnode->next;
if (posnode == NULL)
{
printf("未找到相关信息");
return;
}
}
struct Node*newnode = createnewnode(data);
newnode->next = posnodeback;
posnode->next = newnode;
}
}
表头/表尾/特定位置删除
由于结构体变量的内存是动态申请的,所以当删除一个节点时,要释放该节点指向空间,并使指针指向空指针,这样做是为了防止内存泄漏
表头法删除删除的是头节点后面的一个节点,所以我们只需让第二个节点指向第三个节点(方便下一步),头节点指第三个节点即可
//6 表头法删除
void deletenodebyhead(struct Node*headnode)
{
struct Node*deletenode = headnode->next;
headnode->next = deletenode->next;
free(deletenode);
deletenode = NULL;//释放一段空间时使指针指向空指针,从而不会指向野指针,防止内存泄漏
}
表尾删除的重点在于必须使倒数第二个节点指向空指针,所以还要再创建一个节点最终指向倒数第二个节点,
//7 表尾删除
void deletenodebytail(struct Node*headnode)
{
struct Node*tailnode = headnode;
struct Node* tailnodefront = NULL;
while (tailnode->next != NULL)
{
tailnodefront = tailnode;
tailnode = tailnode->next;
}
free(tailnode);
tailnode = NULL;
tailnodefront->next = NULL;
}
通过数据找到特定的节点,同时另建一个节点指向前一个节点,按照前面的方法找到特点节点后,只需让前一个节点指向特定节点的下一个节点
//8 指定位置删除
void deletenodebyappoint(struct Node*headnode, int posdata)
{
struct Node*posnodefront = headnode;
struct Node*posnode = headnode->next;
if (posnode == NULL)
{
printf("链表为空");
return;
}
else
{
while (posnode->data != posdata)
{
posnodefront = posnode;
posnode = posnodefront->next;
if (posnode == NULL)
{
printf("未找到相关信息");
return;
}
}
posnodefront->next = posnode->next;
free(posnode);
posnode = NULL;
}
}
打印链表
我们需要创建一个移动指针指向第二个节点,从第二个节点开始打印,指针本身即可作为判断条件,打印完一个数据后向后移动,指向下一个节点
//打印链表
void printflist(struct Node*headnode)
{
struct Node*pmove = headnode->next;//从第二个节点开始打印
while (pmove)
{
printf("%d\t", pmove->data);
pmove = pmove->next;
}
printf("\n");
}