本篇实现的单链表,在结构体 single_list_t
中存储的数据域是一个 list_node_t
类型的指针,可根据实际情况对 list_node_t
中的内容增删。
1. single_list.h
#ifndef __SINGLE_LIST_H__
#define __SINGLE_LIST_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
typedef struct list_node_s {
char *data;
int data_count;
} list_node_t;
typedef struct single_list_s {
struct single_list_s *next;
list_node_t *node;
} single_list_t;
int is_list_empty(const single_list_t *head);
int get_list_size(const single_list_t *head);
void print_list_info(const single_list_t *head);
void push_front(single_list_t **head, const char *data);
void push_back(single_list_t **head, const char *data);
void insert(single_list_t **head, single_list_t *pos, const char *data);
void pop_front(single_list_t **head);
void pop_back(single_list_t **head);
void erase(single_list_t **head, single_list_t *pos);
void remove_list_by_data(single_list_t **head, const char *data);
void remove_list_by_all_data(single_list_t **head, const char *data);
void clear_list(single_list_t **head);
void destroy_list(single_list_t **head);
#ifdef __cplusplus
}
#endif
#endif // __SINGLE_LIST_H__
2. single_list.c
#include "single_list.h"
static int s_list_size = 0;
int is_list_empty(const single_list_t *head)
{
return NULL == head;
}
int get_list_size(const single_list_t *head)
{
int list_size = 0;
if (!is_list_empty(head)) {
if (head->node) {
list_size = head->node->data_count;
}
}
return list_size;
}
void print_list_info(const single_list_t *head)
{
const single_list_t *cur = head;
for (; NULL != cur; cur = cur->next) {
if (cur->node) {
printf("%-s -> ", cur->node->data);
}
}
printf("NULL\n");
}
static single_list_t *create_list_node(const char *data)
{
single_list_t *new_list = NULL;
do {
new_list = (single_list_t *)calloc(1, sizeof(single_list_t));
if (NULL == new_list) {
perror("calloc new_list fail");
break;
}
list_node_t *new_node = NULL;
new_node = (list_node_t *)calloc(1, sizeof(list_node_t));
if (NULL == new_node) {
perror("calloc new_node fail");
if (new_list) {
free(new_list);
new_list = NULL;
}
break;
}
new_node->data = (char *)calloc(1, strlen(data) + 1);
if (NULL == new_node->data) {
perror("calloc new_node->data fail");
if (new_node) {
free(new_node);
new_node = NULL;
}
if (new_list) {
free(new_list);
new_list = NULL;
}
break;
}
new_node->data_count = ++s_list_size;
strcpy(new_node->data, data);
new_list->node = new_node;
new_list->next = NULL;
} while (0);
return new_list;
}
void push_front(single_list_t **head, const char *data)
{
single_list_t *new_list = create_list_node(data);
if (NULL == new_list) {
return;
}
new_list->next = *head;
*head = new_list;
}
void push_back(single_list_t **head, const char *data)
{
single_list_t *new_list = create_list_node(data);
if (NULL == new_list) {
return;
}
// 之前如果没有节点,那么不能遍历查找尾节点
if (NULL == *head) {
*head = new_list;
} else {
// 遍历查找尾节点
single_list_t *cur = *head;
while (NULL != cur->next) {
cur = cur->next;
}
new_list->next = cur->next;
cur->next = new_list;
}
}
// 在 pos 前插入节点
void insert(single_list_t **head, single_list_t *pos, const char *data)
{
if (pos == *head) {
push_front(head, data);
return;
}
single_list_t *cur = *head;
single_list_t *new_list = create_list_node(data);
if (NULL == new_list || NULL == pos) {
return;
}
while (pos != cur->next) {
cur = cur->next;
}
new_list->next = pos;
cur->next = new_list;
}
static void free_list_node(single_list_t *pos)
{
if (NULL == pos) {
return;
}
if (pos->node && pos->node->data) {
pos->node->data_count -= 1;
free(pos->node->data);
pos->node->data = NULL;
free(pos->node);
pos->node = NULL;
}
free(pos);
pos = NULL;
}
void pop_front(single_list_t **head)
{
if (is_list_empty(*head)) {
return;
}
single_list_t *cur = *head;
single_list_t *next_list = cur->next;
free_list_node(cur);
*head = next_list;
}
void pop_back(single_list_t **head)
{
if (is_list_empty(*head)) {
return;
}
single_list_t *cur = *head;
// 可能只有一个节点
if (NULL == cur->next) {
*head = cur->next;
free_list_node(cur);
return;
}
// 找到 倒数第二个节点
while (NULL != cur->next->next) {
cur = cur->next;
}
// 最后一个节点
single_list_t *next_list = cur->next;
cur->next = next_list->next;
free_list_node(next_list);
}
void erase(single_list_t **head, single_list_t *pos)
{
if (is_list_empty(*head) || NULL == pos) {
return;
}
if (pos == *head) {
pop_front(head);
return;
}
single_list_t *cur = *head;
while (pos != cur->next) {
cur = cur->next;
}
single_list_t *next_list = pos->next;
cur->next = next_list;
free_list_node(pos);
}
static single_list_t *find_list_by_data(single_list_t *head, const char *data)
{
if (is_list_empty(head) || NULL == data) {
return NULL;
}
single_list_t *cur = head;
for (; NULL != cur; cur = cur->next) {
if (cur->node) {
if (0 == strcmp(cur->node->data, data)) {
return cur;
}
}
}
return NULL;
}
void remove_list_by_data(single_list_t **head, const char *data)
{
single_list_t *pos = find_list_by_data(*head, data);
erase(head, pos);
}
void remove_list_by_all_data(single_list_t **head, const char *data)
{
single_list_t *cur = *head;
single_list_t *next_list = NULL;
// 先 跳过第一个节点
// 假如先删除了第一个节点,那么后续的节点就无法删除
while (NULL != cur->next) {
if (cur->next->node && 0 == strcmp(cur->next->node->data, data)) {
next_list = cur->next;
cur->next = next_list->next;
free_list_node(next_list);
} else {
cur = cur->next;
}
}
// 注意最后删除第一个节点
if ((*head)->node && 0 == strcmp((*head)->node->data, data)) {
pop_front(head);
}
}
void clear_list(single_list_t **head)
{
single_list_t *cur = *head;
single_list_t *next_list = NULL;
if (is_list_empty(cur)) {
return;
}
// 先释放第一个节点后面的节点
for (; NULL != cur->next; cur = next_list) {
next_list = cur->next;
free_list_node(cur);
}
// 释放第一个节点
free_list_node(cur);
*head = NULL;
}
void destroy_list(single_list_t **head)
{
clear_list(head);
}
3. test_single_list.c
#include "single_list.h"
void test()
{
single_list_t *list_head = NULL;
printf("list size : %d\n", get_list_size(list_head));
printf("\nlist info :\n");
print_list_info(list_head);
printf("\npush_front hello\n");
push_front(&list_head, "hello");
printf("\nlist info :\n");
print_list_info(list_head);
printf("\npush_back world\n");
push_back(&list_head, "world");
printf("\nlist info :\n");
print_list_info(list_head);
printf("\ninsert list_head hi\n");
insert(&list_head, list_head, "hi");
printf("\nlist info :\n");
print_list_info(list_head);
printf("\ninsert list_head->next->next emo\n");
insert(&list_head, list_head->next->next, "emo");
printf("\nlist info :\n");
print_list_info(list_head);
printf("\ninsert list_head->next orz\n");
insert(&list_head, list_head->next, "orz");
printf("\nlist info :\n");
print_list_info(list_head);
printf("\npush_front emo\n");
push_front(&list_head, "emo");
printf("\nlist info :\n");
print_list_info(list_head);
printf("\npush_front emo\n");
push_front(&list_head, "emo");
printf("\nlist info :\n");
print_list_info(list_head);
if (is_list_empty(list_head)) {
printf("\nlist is empty\n");
} else {
printf("\nlist is not empty\n");
}
printf("list size : %d\n", get_list_size(list_head));
printf("\nremove_list_by_data emo\n");
remove_list_by_data(&list_head, "emo");
printf("\nlist info :\n");
print_list_info(list_head);
printf("\nremove_list_by_all_data emo\n");
remove_list_by_all_data(&list_head, "emo");
printf("\nlist info :\n");
print_list_info(list_head);
printf("\npop_front\n");
pop_front(&list_head);
printf("\nlist info :\n");
print_list_info(list_head);
printf("\npop_back\n");
pop_back(&list_head);
printf("\nlist info :\n");
print_list_info(list_head);
if (!is_list_empty(list_head)) {
printf("\nerase list_head->next\n");
erase(&list_head, list_head->next);
printf("\nlist info :\n");
print_list_info(list_head);
} else {
printf("\nerase list_head\n");
erase(&list_head, list_head);
printf("\nlist info :\n");
print_list_info(list_head);
}
printf("\nclear list\n");
clear_list(&list_head);
printf("list size : %d\n", get_list_size(list_head));
printf("\nlist info :\n");
print_list_info(list_head);
printf("\ndestroy list\n");
destroy_list(&list_head);
printf("list size : %d\n", get_list_size(list_head));
printf("\nlist info :\n");
print_list_info(list_head);
if (is_list_empty(list_head)) {
printf("\nlist is empty\n");
} else {
printf("\nlist is not empty\n");
}
}
int main(void)
{
test();
return 0;
}
4. Makefile
.PHONY: clean
CC = gcc
CFLAGS = -g -Wall -DDEBUG
SOURCE = $(wildcard ./*.c)
BIN = $(patsubst %.c, %, $(notdir $(SOURCE)))
$(BIN): $(SOURCE)
$(CC) $(CFLAGS) $(SOURCE) -o $@
clean:
rm -rf $(BIN)