对单向的不带环不带头节点的链表做以下操作:
linklist.h
//单向的不带环不带头节点的链表
#pragma once
typedef char LinkNodeType;
typedef struct LinkNode
{
LinkNodeType data;
struct LinkNode *next;
}LinkNode;
typedef LinkNode* PLinkNode;
void LinkListInit(PLinkNode*); //初始化
void LinkListDestroy(PLinkNode*); //销毁
void LinkListPushBack(LinkNode** head,LinkNodeType value); //尾插
void LinkListPopBack(LinkNode** head); //尾删
void LinkListPushFront(LinkNode** head,LinkNodeType value); //头插
void LinkListPopFront(LinkNode** head); //头删
//将一个元素插入到pos之后
void LinkListInsert(LinkNode* pos,LinkNodeType value);
//将一个元素插入到pos之前
void LinkListInsertBefore(LinkNode** head,LinkNode* pos,LinkNodeType value);
//优化后将元素插入到pos之前
void LinkListInsertBefore2(LinkNode* pos,LinkNodeType value);
//删除元素
void LinkListErase(LinkNode** head,LinkNode* pos);
//优化后的删除
void LinkListErase2(LinkNode** head,LinkNode* pos);
//给一个元素找位置
LinkNode* LinkListFind(LinkNode* head,LinkNodeType to_find);
//判断链表是否为空,链表为空返回1,否则,返回0
int LinkListEmpty(LinkNode* head);
//求链表元素的个数
int LinkListSize(LinkNode* head);
//删除指定值的元素
void LinkListRemove(LinkNode** head,LinkNodeType value);
//删除指定值的所有元素
void LinkListRemoveAll(LinkNode** head,LinkNodeType value);
linklist.c
#include"linklist.h"
#include<stdio.h>
#include<stdlib.h>
LinkNode* CreateNode(LinkNodeType value)//创建节点
{
LinkNode* new_node =(LinkNode *)malloc(sizeof(LinkNode));
new_node->data = value;
new_node->next = NULL;
return new_node;
}
void DestroyNode(LinkNode* node)//销毁节点
{
free(node);
}
void LinkListInit(PLinkNode* node)//链表初始化
{
*node = NULL;
}
void LinkListDestroy(LinkNode** phead)//销毁链表
{
if(phead == NULL)
return; //非法输入
if(*phead == NULL)
return; //空链表
LinkNode* cur = *phead;
while(cur != NULL)
{
LinkNode* to_delete = cur;
cur = cur->next;
DestroyNode(to_delete);
}
*phead = NULL;
}
void LinkListPushBack(LinkNode** phead,LinkNodeType value)//尾插
{
if(phead == NULL)
return; //非法输入
if(*phead == NULL)
{
//空链表
*phead = CreateNode(value);
return;
}
//链表非空
LinkNode* cur = *phead;
while(cur->next != NULL)
{
cur = cur->next;
}
LinkNode* new_node = CreateNode(value);
cur->next = new_node;
}
void LinkListPopBack(LinkNode** phead)//尾删
{
if(phead ==NULL)
return; //非法输入
if(*phead == NULL)
return; //单链表
if((*phead)->next == NULL)
{
//链表只有一个元素
DestroyNode(*phead);
*phead = NULL;
return;
}
LinkNode* cur = *phead;
LinkNode* pre = NULL;
while(cur->next != NULL)
{
pre = cur;
cur = cur->next;
}
pre->next = NULL;
DestroyNode(cur);
return;
}
void LinkListPushFront(LinkNode** phead,LinkNodeType value)//头插
{
if(phead == NULL)
return; //非法输入
LinkNode* new_node = CreateNode(value);
new_node->next = *phead;
*phead = new_node;
}
void LinkListPopFront(LinkNode** phead)//头删
{
if(phead == NULL)
return; //非法输入
if(*phead == NULL)
return; //空链表
LinkNode* to_erase = *phead;
*phead = (*phead)->next;
DestroyNode(to_erase);
return;
}
void LinkListInsert(LinkNode* pos,LinkNodeType value)//在pos后面插入一个新节点
{
if(pos == NULL)
return;
//非法输入,pos表示一个节点的指针
//如果pos为空,说明根本不存再这样的节点
LinkNode* new_node = CreateNode(value);
new_node->next = pos->next;
pos->next = new_node;
return;
}
void LinkListInsertBefore(LinkNode** phead,LinkNode* pos,LinkNodeType value)//在pos前面插入一个新节点
{
if(phead == NULL ||pos == NULL)
return; //非法输入
if(pos == *phead)
{
//要插的地方刚好是头节点
LinkListPushFront(phead,value);
return;
}
LinkNode* cur = *phead;
for( ;cur != NULL;cur = cur->next)
{
if(cur->next == pos)
{
break; //跳出循环时cur刚好是pos的前一个节点
}
}
if(cur == NULL)
{
return;
}
LinkListInsert(cur,value);
}
//我们可以看到在pos前面插入新节点时,需要遍历链表,找到它的前一个节点,这种算法时间复杂度为O(n);
//而下面这种算法,通过交换pos位置和新插入节点的数据的方法可以达到同样的目的,时间复杂度为O(1).
void LinkListInsertBefore2(LinkNode* pos,LinkNodeType value)
{
if(pos == NULL)
{
return; //非法输入
}
LinkListInsert(pos,pos->data);
pos->data = value;
//交换新插入的节点和pos的位置
}
void LinkListErase(LinkNode** phead,LinkNode* pos)//删除
{
if((phead == NULL)||(pos == NULL))
return; //非法输入
if(*phead == NULL)
return; //空链表
if(*phead == pos)
LinkListPopFront(phead);//如果pos是起始位置,调用头删
LinkNode* cur = *phead;
for( ;cur != NULL;cur = cur->next)
{
if(cur->next == pos)
{
cur->next = pos->next;
pos->next = NULL;
DestroyNode(pos);
}
}
return;
}
//删除pos位置时,需要遍历链表,找到它的前一个节点,这种算法时间复杂度为O(n);
//而下面这种算法,将pos->next的数据赋给pos然后删除pos->next节点的方法可以达到同样的目的,时间复杂度为O(1).
void LinkListErase2(LinkNode** phead,LinkNode* pos)
{
if((phead == NULL)||(pos == NULL))
return; //非法输入
if(*phead == NULL)
return; //空链表
pos->data = pos->next->data;
LinkNode* to_erase = pos->next;
pos->next = to_erase->next;
DestroyNode(to_erase);
return;
}
LinkNode* LinkListFind(LinkNode* phead,LinkNodeType to_find)//找指定元素的位置
{
if(phead == NULL)
return NULL; //空链表
LinkNode* cur = phead;
while(cur != NULL)
{
if(cur->data == to_find)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
int LinkListEmpty(LinkNode* phead)//判断链表是否为空
{
if(phead == NULL)
{
return 1; //空链表
}
else
{
return 0;
}
}
int LinkListSize(LinkNode* phead)//求链表大小
{
if(phead == NULL)
return; //空链表
LinkNode* cur = phead;
size_t count = 0;
for( ;cur != NULL;cur = cur->next)
{
count++;
}
return count;
}
void LinkListRemove(LinkNode** phead,LinkNodeType value)//移除指定值的元素
{
if(phead == NULL)
return; //非法输入
if(*phead == NULL)
return; //空链表
LinkNode* cur = LinkListFind(*phead,value);
if(cur == NULL)
{
return; //没找到
}
LinkListErase(phead,cur);
}
void LinkListRemoveAll(LinkNode** phead,LinkNodeType value)//移除指定值的所有元素
{
if(phead == NULL)
return; //非法输入
if(*phead == NULL)
return; //空链表
while(1)
{
LinkNode* cur = LinkListFind(*phead,value);
if(cur == NULL)
{
return;
}
LinkListErase(phead,cur);
}
}
///
//以下是测试代码
///
#include<stdio.h>
#define TEST_HEADER printf("\n=====================%s====================\n",__FUNCTION__)
void LinkListPrintChar(LinkNode* head,const char* msg)
{
printf("[%s]\n",msg);
LinkNode* cur = head;
for( ;cur != NULL;cur = cur->next)
{
printf("[%c|%p] ",cur->data,cur);
}
printf("\n");
}
void TestInit()
{
TEST_HEADER;
LinkNode* head;
LinkListInit(&head);
}
void TestPushBack()
{
TEST_HEADER;
LinkNode* head;
LinkListInit(&head);
LinkListPushBack(&head,'a');
LinkListPushBack(&head,'b');
LinkListPushBack(&head,'c');
LinkListPushBack(&head,'d');
LinkListPrintChar(head,"尾插四个元素");
}
void TestPopBack()
{
TEST_HEADER;
LinkNode* head;
LinkListInit(&head);
LinkListPopBack(&head);
LinkListPrintChar(head," 对空链表尾删");
LinkListPushBack(&head,'a');
LinkListPopBack(&head);
LinkListPrintChar(head,"对只有一个元素的链表尾删");
LinkListPushBack(&head,'a');
LinkListPushBack(&head,'b');
LinkListPushBack(&head,'c');
LinkListPushBack(&head,'d');
LinkListPopBack(&head);
LinkListPopBack(&head);
LinkListPrintChar(head,"尾删两个元素");
LinkListPopBack(&head);
LinkListPopBack(&head);
LinkListPrintChar(head,"再尾删两个元素");
}
void TestPushFront()
{
TEST_HEADER;
LinkNode* head;
LinkListInit(&head);
LinkListPushFront(&head,'a');
LinkListPushFront(&head,'b');
LinkListPushFront(&head,'c');
LinkListPushFront(&head,'d');
LinkListPrintChar(head,"头插四个元素");
}
void TestPopFront()
{
TEST_HEADER;
LinkNode* head;
LinkListInit(&head);
LinkListPopFront(&head);
LinkListPrintChar(head,"对空链表头删");
LinkListPushFront(&head,'a');
LinkListPushFront(&head,'b');
LinkListPushFront(&head,'c');
LinkListPushFront(&head,'d');
LinkListPrintChar(head,"头插四个元素");
LinkListPopFront(&head);
LinkListPopFront(&head);
LinkListPrintChar(head,"头删两个元素");
LinkListPopFront(&head);
LinkListPopFront(&head);
LinkListPrintChar(head,"再头删两个元素");
}
void TestInsert()
{
TEST_HEADER;
LinkNode* head;
LinkListInit(&head);
LinkListPushBack(&head,'a');
LinkListPushBack(&head,'b');
LinkListPushBack(&head,'c');
LinkListPushBack(&head,'d');
LinkNode* pos = head->next;
LinkListInsert(pos,'x');
LinkListPrintChar(head,"插入'x'元素");
}
void TestInsertBefore()
{
TEST_HEADER;
LinkNode* head;
LinkListInit(&head);
LinkListPushBack(&head,'a');
LinkListPushBack(&head,'b');
LinkListPushBack(&head,'c');
LinkListPushBack(&head,'d');
LinkNode* pos1 = head;
LinkListInsertBefore(&head,pos1,'x');
LinkListPrintChar(head,"向头节点之前插入'x'元素");
LinkNode* pos2 = head->next->next;
LinkListInsertBefore(&head,pos2,'y');
LinkListPrintChar(head,"向'b'之前插入'y'元素");
}
void TestInsertBefore2()
{
TEST_HEADER;
LinkNode* head;
LinkListInit(&head);
LinkListPushBack(&head,'a');
LinkListPushBack(&head,'b');
LinkListPushBack(&head,'c');
LinkListPushBack(&head,'d');
LinkNode* pos1 = head;
LinkListInsertBefore(&head,pos1,'x');
LinkListPrintChar(head,"向头节点之前插入'x'元素");
LinkNode* pos2 = head->next->next;
LinkListInsertBefore(&head,pos2,'y');
LinkListPrintChar(head,"向'b'之前插入'y'元素");
}
void TestErase()
{
TEST_HEADER;
LinkNode* head;
LinkListInit(&head);
LinkListErase(&head,(LinkNode*)0x11);
LinkListPrintChar(head,"尝试对空链表删除");
LinkListPushBack(&head,'a');
LinkListPushBack(&head,'b');
LinkListPushBack(&head,'c');
LinkListPushBack(&head,'d');
LinkNode* pos= head;
LinkListErase(&head,pos);
LinkListPrintChar(head,"删除元素'a'");
LinkNode* pos2 = (LinkNode*)0x10;
LinkListErase(&head,pos2);
LinkListPrintChar(head,"尝试对一个不存在的位置删除");
}
void TestErase2()
{
TEST_HEADER;
LinkNode* head;
LinkListInit(&head);
LinkListErase(&head,(LinkNode*)0x11);
LinkListPrintChar(head,"尝试对空链表删除");
LinkListPushBack(&head,'a');
LinkListPushBack(&head,'b');
LinkListPushBack(&head,'c');
LinkListPushBack(&head,'d');
LinkNode* pos = head->next;
LinkListErase(&head,pos);
LinkListPrintChar(head,"删除元素'b'");
LinkNode* pos2 = (LinkNode*)0x10;
LinkListErase(&head,pos2);
LinkListPrintChar(head,"尝试对一个不存在的位置删除");
}
void TestFind()
{
TEST_HEADER;
LinkNode* head;
LinkListInit(&head);
LinkNode* pos = LinkListFind(head,'a');
printf("'a'的地址是:%p\n",pos);
LinkListPushBack(&head,'a');
LinkListPushBack(&head,'b');
LinkListPushBack(&head,'c');
LinkListPushBack(&head,'d');
LinkNode* pos1 = LinkListFind(head,'c');
printf("'c'的地址是:%p\n",pos1);
LinkNode* pos2 = LinkListFind(head,'x');
printf("'x'的地址是:%p",pos2);
}
void TestEmpty()
{
TEST_HEADER;
LinkNode* head;
LinkListInit(&head);
size_t cur1 = LinkListEmpty(head);
printf("%d\n",cur1);
LinkListPushBack(&head,'a');
LinkListPushBack(&head,'b');
LinkListPushBack(&head,'c');
LinkListPushBack(&head,'d');
size_t cur2 = LinkListEmpty(head);
printf("%d",cur2);
}
void TestSize()
{
TEST_HEADER;
LinkNode* head;
LinkListInit(&head);
size_t cur1 = LinkListSize(head);
printf("%d\n",cur1);
LinkListPushBack(&head,'a');
LinkListPushBack(&head,'b');
LinkListPushBack(&head,'c');
LinkListPushBack(&head,'d');
size_t cur2 = LinkListSize(head);
printf("%d",cur2);
}
void TestRemove()
{
TEST_HEADER;
LinkNode* head;
LinkListInit(&head);
LinkListRemove(&head,'a');
LinkListPrintChar(head,"尝试对空链表删除");
LinkListPushBack(&head,'a');
LinkListPushBack(&head,'b');
LinkListPushBack(&head,'c');
LinkListPushBack(&head,'d');
LinkListRemove(&head,'a');
LinkListPrintChar(head,"删除元素'a'");
LinkListRemove(&head,'x');
LinkListPrintChar(head,"尝试删除一个不存在的值");
}
void TestRemoveAll()
{
TEST_HEADER;
LinkNode* head;
LinkListInit(&head);
LinkListRemoveAll(&head,'a');
LinkListPrintChar(head,"尝试对空链表删除");
LinkListPushBack(&head,'a');
LinkListPushBack(&head,'b');
LinkListPushBack(&head,'a');
LinkListPushBack(&head,'c');
LinkListPushBack(&head,'a');
LinkListPushBack(&head,'d');
LinkListPushBack(&head,'a');
LinkListRemoveAll(&head,'a');
LinkListPrintChar(head,"删除元素'a'");
LinkListRemoveAll(&head,'x');
LinkListPrintChar(head,"尝试删除一个不存在的值");
}
int main()
{
TestInit();
TestPushBack();
TestPopBack();
TestPushFront();
TestPopFront();
TestInsert();
TestInsertBefore();
TestInsertBefore2();
TestErase();
TestErase2();
TestFind();
TestEmpty();
TestSize();
TestRemove();
TestRemoveAll();
printf("\n");
return 0;
}
注意:对链表操作时要看传入的是一级指针还是二级指针,修改头指针的指向用二级指针,其他用一级指针。