单向链表的操作
实现功能:创建链表、头插、尾插、头删除、尾删除、遍历打印、删除预设值相同的节点、重设值、去重、翻转、排序、清空、释放。
测试代码在文章末尾。
#include "linklist.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*typedef struct _node{
int data;
struct _node* next;
}LinkList_t;
#define LinkList_t List_t
*/
/************************************
* @b 创建链表的头
* ***********************************/
List_t* list_creat(void)
{
List_t* list = NULL;
if((list = (List_t*)malloc(sizeof(List_t))) == NULL)
{
printf("Failed malloc to creat list");
return NULL;
}
list->data = 0;
list->next = NULL;
return list;
}
/************************************
* @b 创建链表的一个节点
* ***********************************/
List_t* list_creat_node(data_t _data)
{
List_t* node = (List_t*)malloc(sizeof(List_t));
if(node == NULL)
{
printf("Failed malloc to creat node\n");
return NULL;
}
node->data = _data; /*给新结点的数据赋值*/
node->next = NULL; /*把新节点的下一个,指向NULL*/
return node;
}
/************************************
* @b 判断链表是否为空
* ***********************************/
int list_empty(List_t* head)
{
return head->next == NULL ? -1:0;
}
/************************************
* @b 头插法
* ***********************************/
int list_insert_head(List_t* head,data_t val)
{
List_t* node = list_creat_node(val); /*创建一个新节点并判断是否成功*/
if(node == NULL)
{
printf("Failed insert head\n");
return -1;
}
node->next = head->next; /*把新节点的下一个,指向头所指的下一个*/
head->next = node; /*把头所指的下一个,指向新节点*/
return 0;
}
/************************************
* @b 尾插法
* ***********************************/
int list_insert_tail(List_t* head,data_t val)
{
List_t* node = list_creat_node(val); /*创建一个新节点并判断是否成功*/
if(node == NULL)
{
printf("Fail insert tail\n");
return -1;
}
while (head->next != NULL) /*遍历链表找到结尾*/
{
head = head->next;
}
head->next = node; /*把结尾所指的下一个,指向新节点*/
return 0;
}
/************************************
* @b 头删
* ***********************************/
int list_delete_head(List_t* head)
{
List_t* p = NULL;
if(list_empty(head)) /*判断节点是否为空*/
{
printf("Failed delete ,list is empty\n");
return -1;
}
p = head->next;
head->next = head->next->next; /*把头所指的下一个,指向新节点*/
free(p);
p = NULL;
return 0;
}
/************************************
* @b 尾删
* ***********************************/
int list_delete_tail(List_t* head)
{
List_t* p = NULL;
if(list_empty(head)) /*判断节点是否为空*/
{
printf("Failed delete tail,list is empty\n");
return -1;
}
while (head->next != NULL) /*遍历链表找到结尾*/
{
p = head; /*当head是结尾时,p是倒数第二个*/
head = head->next;
}
free(head);
head = NULL;
p->next = NULL;
return 0;
}
/***********************************
*@b 删除链表当中所有和用户值相同的节点
**********************************/
int list_delete_data(List_t* head,data_t val)
{
List_t* p = NULL;
int res = 0;
if(list_empty(head)) /*判断节点是否为空*/
{
printf("Failed delete data,list is empty\n");
return -1;
}
while (head->next != NULL) /*遍历链表到结尾*/
{
p = head->next; /*复制下一个节点地址*/
if((p->data) == val) /*如果节点的值和用户预设值一样*/
{
head->next = p->next; /*把之前的节点链接到这个要删除的节点之后*/
free(p); /*删除这个节点*/
p = NULL;
res++; /*删除计数+1*/
}
else /*否则节点的值和用户预设不一样*/
{
head = head->next; /*指向下一个结点*/
}
}
return res; /*返回删除节点的个数*/
}
/**********************************
*@b 重设节点
* ********************************/
int list_reset_data(List_t* head,int old,int new)
{
int res = 0;
if(list_empty(head)) /*判断节点是否为空*/
{
printf("Failed reset data,list is empty\n");
return -1;
}
while (head->next != NULL) /*遍历链表找到结尾*/
{
if(((head->next)->data) == old) /*找出所有和用户预设值一样的节点并更改数据值*/
{
((head->next)->data) = new;
res++;
}
else
{
head = head->next; /*把头指向新节点*/
}
}
return res; /*返回更改节点的个数*/
}
/*****************************************************************
*
* p q
* head head->next dest->next q->next (NULL)
* _________ _________ _________
* |\\\\\\\| |____1____| |____1____| |____2____|
* ^^^ same ^^^
* |||--------------|||
* (delete this)
* ******************************************************************/
/**********************************
*@b 单向链表去重
* ********************************/
int list_delete_duplicate(List_t* head)
{
List_t* p = NULL;
List_t* q = NULL;
int cnt = 0;
if(list_empty(head)) /*判断节点是否为空*/
{
printf("Failed delete duplicate,list is empty\n");
return -1;
}
for(;head->next != NULL;head = head->next)
{
p = head->next;
while(p->next != NULL)
{
q = p->next;
if(q->data == head->next->data)
{
p->next = q->next;
free(q);
q = NULL;
cnt++;
}
else
{
p = p->next;
}
}
}
return cnt;
}
#if 0
int list_delete_duplicate(List_t* head)
{
List_t* dest = NULL;
List_t* src = NULL;
int cnt = 0;
while (head->next != NULL)
{
dest = head->next;
while (dest->next != NULL)
{
src = dest->next;
if(head->next->data == src->data)//不要移动dest,防止跳过后面相同的节点
{
dest->next = src->next; //删除中间相同的节点
free(src);
src = NULL;
cnt++;
}
else
{
dest = dest->next; //跳过不相同的节点
}
}
head = head->next;
}
return cnt; /*返回删除节点的个数*/
}
#endif
/***********************************
*@b 翻转链表
**********************************/
int list_reverse(List_t** head) /*为什么要用到二级指针*/
{ /*因为我们需要更传参的值,所以要用到传参的地址*/
List_t* new = NULL;
List_t* p = NULL;
if(list_empty(*head)) /*判断链表是否为空*/
{
printf("Failed reverse,list is empty\n");
return -1;
}
if((new = list_creat()) == NULL)
{
printf("Failed reverse,can not creat new list\n");
return -1;
}
while ((*head)->next != NULL)
{
p = (*head)->next;
(*head)->next = (*head)->next->next;
p->next = new->next;
new->next = p;
}
free(*head);
*head = new;
return 0;
}
/***********************************
*@b 链表排序
**********************************/
int list_sort(List_t* head)
{
List_t* p = NULL;
List_t* q = NULL;
if(list_empty(head)) /*判断链表是否为空*/
{
printf("Failed sort,list is empty\n");
return -1;
}
for(;head->next->next != NULL;head = head->next)
{
p = head->next;
while (p->next != NULL)
{
q = p->next;
if(q->data < head->next->data)
{
p->next = p->next->next;
q->next = head->next;
head->next = q;
}
else
{
p = p->next;
}
}
}
return 0;
}
/***********************************
*@b 遍历打印
**********************************/
int list_print(List_t* head)
{
if(list_empty(head)) /*判断节点是否为空*/
{
printf("Failed print,list is empty\n");
return -1;
}
while (head->next != NULL) /*遍历链表找到结尾*/
{
head = head->next; /*打印之前先跳过头(头不存放数据)*/
printf("%-3d",head->data);
}
putchar('\n');
return 0;
}
/***********************************
*@b 清空链表
**********************************/
void list_clean(List_t* head)
{
List_t* p = NULL;
while (head->next != NULL) /*遍历链表找到结尾*/
{
p = head->next; /*复制头所指的节点地址*/
head->next = head->next->next; /*把头指向新节点*/
free(p);
p = NULL;
}
}
/***********************************
*@b 释放链表
**********************************/
void list_free(List_t* head)
{
if(head != NULL)
{
list_clean(head);
free(head);
head = NULL;
}
}