【数据结构】不带头节点的单链表

本文介绍了单链表的实现,包括头插法、尾插法、插入指定位置、删除节点等功能。代码示例展示了如何在C语言中创建和管理单链表,以及对链表进行各种操作,如获取链表长度、打印链表信息等。此外,还提供了测试用例来验证链表操作的正确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本篇实现的单链表,在结构体 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)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值