以下操作针对不带头结点不带环的的单向链表
首先linklist.h头文件代码:
#pragma once
typedef char LinkNodeType;
typedef struct LinkNode {
LinkNodeType data;
struct LinkNode* next;
}LinkNode;
//初始化链表
void LinkListInit (LinkNode** node);
//创建结点
LinkNode* CreateNode(LinkNodeType value);
//销毁节点
void DestroyNode(LinkNode*);
//链表尾部插入一个元素
//**是因为当链表为空链表是需要修改头节点
void LinkListPushBack(LinkNode** head , LinkNodeType value);
//删除链表尾部元素
void LinkListPopBack(LinkNode** head );
//头插
void LinkListPushFront(LinkNode** head ,LinkNodeType value);
//头删
void LinkListPopFront(LinkNode** head );
//在Pos之后插入一个结点
void LinkListInsertAfter(LinkNode* head ,LinkNode* pos ,LinkNodeType value);
//在pos之前插入一个结点
void LinkListInsertBefore(LinkNode** head ,LinkNode* pos, LinkNodeType value);
//查找任意位置的节点
LinkNode* LinkListFind(LinkNode* head , LinkNodeType pos);
//删除指定位置的元素
void LinkListErase(LinkNode** head,LinkNode* pos);
//删除指定值的元素
void LinkListRemove(LinkNode** head,LinkNodeType value);
//指定值的所有元素都删掉
void LinkListRemoveAll(LinkNode** head ,LinkNodeType value);
//求链表的长度
int LinkListSize(LinkNode* head);
//初始化链表
思想:单链表不带头结点,即链表的head == NULL表示空链表。
注:因是对head做修改,所以必须传指针。
代码如下:
void LinkListInit(LinkNode** head) {
*head = NULL;
}
//创建结点
实现函数如下:
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);
}
//尾插
思想:首先创建一个新结点new_node,在遍历链表找到链表的尾结点cur,最后修改cur的next的指向。
注:如果为空链表尾插,需要给head赋值,对head做修改,所以这里head需传指针;
代码如下:
void LinkListPushBack(LinkNode** head , LinkNodeType value) {
if(head == NULL) {
//非法输入
return;
}
if(*head == NULL) {
//为空链表
*head = CreateNode(value);
return;
}
//链表非空
LinkNode* cur = *head;
while(cur->next != NULL) {
cur = cur->next;
}
LinkNode* new_node = CreateNode(value);
cur->next = new_node;
new_node->next = NULL;
}
//尾删
思想:遍历链表找到最后一个要删除的元素的前一个元素prev,将prev置成NULL,在销毁prev的next即最后一个元素。
代码如下:
void LinkListPopBack(LinkNode** head) {
if(head == NULL) {
//非法输入
return;
}
if(*head == NULL) {
//空链表
return;
}
if((*head)->next == NULL) {
//只有一个元素
DestroyNode(*head);
*head == NULL;
return;
}
LinkNode* cur = *head;
LinkNode* pre = NULL;
while(cur->next != NULL) {
pre = cur;
cur = cur->next;
}
LinkNode* to_delete = pre->next;
pre->next == NULL;
DestroyNode(to_delete);
return;
}
//头插
思想:头插是要修改head指针,所以必须传指针,创建一个新结点,使之新结点的next指向head,在将新结点修改为头指针head;
代码如下:
void LinkListPushFront(LinkNode** head , LinkNodeType value) {
if(head == NULL) {
//非法输入
return;
}
LinkNode* new_node = CreateNode(value);
if(*head == NULL) {
//空链表
new_node->next = NULL;
*head = new_node;
return;
}
new_node->next = *head;
*head = new_node;
return;
}
//头删
思想:先定义一个指针to_delete指向head,在将to_delete->next修改为head,在销毁to_delete指针;
代码如下:
void LinkListPopFront(LinkNode** head) {
if(head == NULL) {
//非法输入
return;
}
if(*head == NULL) {
// 空链表
return;
}
LinkNode* to_delete = *head;
*head = to_delete->next;
DestroyNode(to_delete);
return;
}
//在pos之前插入
思想:先遍历链表找到Pos的前一个位置prev,在创建一个结点new_node最后修改prev 的next和new_node的next,这里需要注意的是必须先修改new_node的next使之指向pos,在去修改prev的next,如果先修改的prev 的next则pos之后的结点就找不到了;
代码如下:
void LinkListInsertBefore(LinkNode** head, LinkNode* pos, LinkNodeType value) {
if(head == NULL ||pos == NULL) {
return;
}
if(*head == NULL) {
return;
}
LinkNode* new_node = CreateNode(value);
if(pos == (*head)) {
new_node->next = *head;
*head = new_node;
return;
}
LinkNode* prev = *head;
for(; prev != pos ; prev=prev->next) {
if(prev->next == pos) {
break;
}
}
if(prev == NULL) {
//pos不存在
return;
}
new_node->next = prev->next;
prev->next = new_node;
return;
}
//在pos之后插入
思想:首先创建一个新结点,在修改新结点的next,和修改pos的next;
代码如下:
void LinkListInsertAfter(LinkNode* head, LinkNode* pos, LinkNodeType value) {
if(head == NULL) {
// 空链表
return;
}
if(pos == NULL) {
//pos 位置非法
return;
}
LinkNode* new_node = CreateNode(value);
new_node->next = pos->next;
pos->next = new_node;
return;
}
//不遍历链表在pos之前插入一个元素
思想:通过交换值得放法,这里直接调用之前的pos之后插入的函数将pos值插入到pos之后,在将要插入的值赋给pos的data;
代码如下:
void LinkListInsertBefore2(LinkNode* head ,LinkNode* pos ,LinkNodeType value) {
if(head == NULL||pos == NULL) {
//非法输入
return;
}
LinkListInsertAfter(head , pos ,pos->data);
pos->data = value;
return;
}
//查找任意位置的元素思想:遍历链表判断链表中的值是否与指定的值相等,相等则返回指针,找不到则返回NULL;
代码如下:
LinkNode* LinkListFind(LinkNode* head , LinkNodeType pos) {
if(head == NULL) {
//空链表
return NULL;
}
LinkNode* cur = head;
while(cur != NULL) {
if(cur->data == pos) {
return cur;
}
cur = cur->next;
}
return NULL;
}
//删除指定位置的元素
思想:要删除Pos位置的元素,必须找到pos的前一个元素,最后修改Pos的前一个元素的next指向;
代码如下:
void LinkListErase(LinkNode** head ,LinkNode* pos) {
if(head == NULL || pos == NULL) {
//非法输入
return;
}
if(*head == NULL) {
//空链表
return;
}
if(pos == *head) {
LinkListPopFront(&pos);
return;
}
LinkNode* cur = *head;
for(; cur != NULL;cur=cur->next) {
if(cur->next == pos) {
break;
}
}
LinkNode* to_delete = cur->next;
cur->next = pos->next;
DestroyNode(to_delete);
return;}
//删除指定值得元素
思想:遍历链表判断与要删除的值是否相等,最主要的思想为删除时需要找到要删除的值得前一个元素,然后修改指针的指向,最后销毁结点;
代码如下:
void LinkListRemove(LinkNode** head, LinkNodeType value) {
if(head == NULL) {
return;
}
LinkNode* cur = *head;
if((*head)->data == value) {
LinkListPopFront(&cur);
return;
}
for(;cur->next->next != NULL;cur=cur->next) {
if(cur->next->data == value) {
LinkNode* to_delete = cur->next;
cur->next = to_delete->next;
DestroyNode(to_delete);
return;
}
}
return;
}
//删除指定元素的的所有值
思想:死循环查找所要删除的值在调用之前的删除位置的函数删除所有元素;
代码如下:
void LinkListRemoveAll(LinkNode** head ,LinkNodeType value) {
if(head == NULL) {
return;
}
if(*head == NULL) {
return;
}
while(1){
LinkNode* cur = LinkListFind(*head,value);
if(cur == NULL) {
return;
}
LinkListErase(head,cur);
}
}
//求链表的长度
思想:遍历链表,指针每走一步计数器加一;
代码如下:
int LinkListSize(LinkNode* head) {
if(head == NULL){
//空链表
return 0;
}
int count = 0;
LinkNode* cur = head;
while(cur != NULL) {
cur = cur->next;
count++;
}
return count;
}