单链表(不带头节点,不带环)的C语言实现代码
注:建议结合单链表(基础版)一起来看,因为进击版中的一些功能的实现调用了基础版的一些函数(已标出)可以简化功能实现。
//在pos前插入元素,不遍历整个链表
//在pos后插入元素
//删除指定位置元素
//删除指定的元素
//删除指定所有元素
//判断链表是否为空
//求链表长度
//逆序打印单链表
头文件link.h
#pragma once //防止头文件重复包含
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define Datatype char
typedef struct LinkNode //定义结构体
{
Datatype data; //存储内容
struct LinkNode* next; //指向下一个节点
}LinkNode;
//在pos前插入元素,不遍历整个链表
void LinklistInsert(LinkNode** phead, LinkNode* pos, Datatype value);
//在pos后插入元素
void LinklistInsertAfter(LinkNode** phead, LinkNode* pos, Datatype value);
//删除指定位置元素
void LinklistErase(LinkNode** phead, LinkNode* pos);
//删除指定的元素
void LinklistRemove(LinkNode** phead, Datatype to_remove);
//删除指定所有元素
void LinklistRemoveAll(LinkNode** phead, Datatype to_remove);
//判断链表是否为空
int LinklistEmpty(LinkNode* head);
//求链表长度
size_t LinklistSize(LinkNode* head);
//逆序打印单链表
void LinklistReversePrint(LinkNode* head);
//以上功能实现需要用到的(声明函数如下)
//初始化链表头节点
void LinklistInit(LinkNode** phead);
//链表尾插
void LinklistPushback(LinkNode** phead, Datatype value);
//链表尾删
void LinklistPopback(LinkNode** phead);
//查找元素在链表中的地址
LinkNode* LinklistFind(LinkNode* head, Datatype to_find);
功能实现link.c
//初始化链表头节点
void LinklistInit(LinkNode** phead)
{
if (phead == NULL)
{
printf("空指针");
return;
}
*phead = NULL;
}
//任意位置插入(pos前),不遍历整个链表
void LinklistInsert(LinkNode** phead, LinkNode* pos, Datatype value)
{
if (phead == NULL||pos==NULL)
{
printf("非法输入");
return;
}
//如果pos在第一个位置则调用头插
if (*phead == pos)
{
LinklistPushfront(phead, value);
return;
}
//常规前插,乾坤大挪移
LinkNode* new = LinklistCreat();
new->data = pos->data; // 把pos值拷贝给新节点
new->next = pos->next; //pos指向赋给new指向
pos->data = value; //将pos信息修改为新节点信息
pos->next = new; //pos指向new
}
//任意位置插入(pos后)
void LinklistInsertAfter(LinkNode** phead, LinkNode* pos, Datatype value)
{
if (phead == NULL|| pos == NULL)
{
printf("非法输入");
return;
}
if (*phead == NULL )
{
printf("空链表");
return;
}
LinkNode* new = LinklistCreat();
new->data = value;
new->next = pos->next;
pos->next = new; //pos下一个节点指向新节点
}
//删除指定位置元素
void LinklistErase(LinkNode** phead, LinkNode* pos)
{
if (phead == NULL || pos == NULL)
{
printf("非法输入");
return;
}
if (*phead == NULL)
{
printf("空链表");
return;
}
//第一个位置为pos
if (*phead == pos)
{
LinkNode* tmp = *phead;
*phead = (*phead)->next;
LinklistDestroy(pos);
return;
}
//常规位置删除
LinkNode* cur = *phead;
LinkNode* pre = NULL;
while (cur != NULL)
{
if (cur == pos)
{
LinkNode* tmp = cur;
pre->next = cur->next;
LinklistDestroy(tmp);
return;
}
pre = cur;
cur = cur->next;
}
return;
}
//删除指定值的元素
void LinklistRemove(LinkNode** phead, Datatype to_remove) {
if (phead == NULL)
{
printf("非法输入");
return;
}
if (*phead == NULL)
{
printf("空链表");
return;
}
//删除第一个元素
if ((*phead)->data == to_remove) {
LinklistPopfront(phead); //调用头删
return;
}
LinkNode* cur = LinklistFind(*phead, to_remove); //调用查找函数,根据元素查找地址
LinklistErase(phead, cur); //调用删除函数, 根据地址删除对应元素
}
//删除指定所有元素
void LinklistRemoveAll(LinkNode** phead, Datatype to_remove)
{
if (phead == NULL)
{
printf("非法输入");
return;
}
//空链表
if (*phead == NULL)
{
return;
}
//删除第一个元素
if ((*phead)->data == to_remove)
{
LinklistPopfront(phead); //调用头删
}
LinkNode* cur = LinklistFind(*phead, to_remove);
while (to_remove != NULL && cur != NULL) //遍历删除指定元素
{
LinklistErase(phead, cur);
cur = LinklistFind(*phead, to_remove);
}
}
//链表为空
int LinklistEmpty(LinkNode* head)
{
if (head == NULL)
{
return 1; //链表为空返回1
}
return 0; //否则返回随机值
}
//链表长度
size_t LinklistSize(LinkNode* head)
{
if (head == NULL)
{
printf("非法输入");
return;
}
size_t count = 0; //定义计数器
LinkNode* cur = head;
for (; cur != NULL; cur = cur->next)
{
if (cur != NULL)
{
count++;
}
}
return count;
}
//逆序打印链表
void LinklistReversePrint(LinkNode* head)
{
if (head == NULL)
{
printf("空链表");
return;
}
LinklistReversePrint(head->next); //递归实现逆序
printf("%c\n", head->data);
}
(以上功能的实现需要调用到以下函数,即附如下函数)
//查找元素在链表中的地址
LinkNode* LinklistFind(LinkNode* head, Datatype to_find)
{
if (head == NULL)
{
printf("空链表");
return NULL ;
}
LinkNode *cur = head;
while (cur != NULL)
{
if (cur->data == to_find)
{
return cur; //找到则返回结构体地址
}
cur = cur->next; //遍历要查找的元素
}
printf("没有找到\n");
return NULL;
}
//链表尾删
void LinklistPopback(LinkNode** phead)
{
if (phead == NULL)
{
printf("非法输入");
return;
}
if (*phead == NULL)
{
printf("空链表");
return;
}
//只有一个元素
if ((*phead)->next == NULL)
{
LinkNode* tmp = *phead; //保存头指针指向
*phead = NULL; //置空
LinklistDestroy(tmp); //销毁节点
return;
}
//两个及以上元素
LinkNode* cur = *phead;
LinkNode* pre = NULL;
while (cur->next != NULL) //使cur指向最后一个节点
{ //使pre指向倒数第二个节点
pre = cur;
cur = cur->next;
}
pre->next = NULL; //尾删,即倒数第二个节点指向空
LinklistDestroy(cur); //销毁最后一个节点
}
//链表尾插
void LinklistPushback(LinkNode** phead, Datatype value)
{
if (phead == NULL)
{
printf("非法输入");
return;
}
//空链表尾插
if (*phead == NULL)
{
*phead = LinklistCreat(); //创建节点
(*phead)->data = value; //节点赋值
(*phead)->next = NULL; //插入空链表即新节点指向空
return;
}
//常规尾插
LinkNode* new = LinklistCreat(); //创建新节点
LinkNode* cur = *phead;
new->data = value;
new->next = NULL;
while (cur->next!= NULL) //使cur指向最后一个节点
{
cur = cur->next;
}
cur->next = new; //最后节点的下一个节点即指向新节点
return;
}
功能测试 test.c
#include "link.h"
#include<stdio.h>
#include<stdlib.h>
/************************************************************************
* tset
***********************************************************************/
//定义一个宏来打印调试函数提示信息
#define FUNCTION() printf("**************** %s ************\n" , __FUNCTION__)
void printChar(LinkNode* head ,const char *msg)
{
if (head == NULL)
{
printf("空指针");
return;
}
printf("%s\n", msg);
for (; head != NULL; head = head->next)
{
printf("%c\n", head->data);
}
printf("\n");
return;
}
void TestInsert()
{
FUNCTION();
LinkNode* head;
LinklistInit(&head);
LinklistPushback(&head, 'a');
LinklistPushback(&head, 'b');
LinklistPushback(&head, 'c');
LinklistPushback(&head, 'd');
printChar(head, "尾插a,b,c,d");
LinklistInsert(&head, head ,'x');
printChar(head, "a之前插入x");
}
void TestInsertAfter()
{
FUNCTION();
LinkNode* head;
LinklistInit(&head);
LinklistPushback(&head, 'a');
LinklistPushback(&head, 'b');
LinklistPushback(&head, 'c');
LinklistPushback(&head, 'd');
printChar(head, "尾插a,b,c,d");
LinklistInsertAfter(&head, head->next, 'x');
printChar(head, "b之后插入x");
}
void TestErase()
{
FUNCTION();
LinkNode* head;
LinklistInit(&head);
LinklistPushback(&head, 'a');
LinklistPushback(&head, 'b');
LinklistPushback(&head, 'c');
LinklistPushback(&head, 'd');
printChar(head, "尾插a,b,c,d");
LinklistErase(&head, head);
printChar(head, "删除头节点的元素a");
}
void TestRemove()
{
FUNCTION();
LinkNode* head;
LinklistInit(&head);
LinklistPushback(&head, 'a');
LinklistPushback(&head, 'b');
LinklistPushback(&head, 'c');
LinklistPushback(&head, 'd');
printChar(head, "尾插a,b,c,d");
LinklistRemove(&head, 'a');
printChar(head, "删除指定元素a");
}
void TestSize()
{
FUNCTION();
LinkNode* head;
LinklistInit(&head);
LinklistPushback(&head, 'a');
LinklistPushback(&head, 'b');
LinklistPushback(&head, 'c');
LinklistPushback(&head, 'd');
LinklistSize(head);
size_t count = LinklistSize(head);
printf("count=%lu\n", count);
printChar(head, "求链表元素的个数");
}
void TestEmpty()
{
FUNCTION();
LinkNode* head;
LinklistInit(&head);
LinklistPushback(&head, 'a');
LinklistPushback(&head, 'b');
LinklistPushback(&head, 'c');
LinklistPushback(&head, 'd');
LinklistPopback(&head);
LinklistPopback(&head);
LinklistEmpty(head);
int i = LinklistEmpty(head);
printf("i=%d\n", i);
printChar(head, "判断链表是否为空");
}
int main()
{
TestInsert();
TestInsertAfter();
TestErase();
TestRemove();
TestEmpty();
TestSize();
return 0;
}