单链表(C语言,手撕)

1. 手撕单链表

  1. 节点定义:ListTable
  2. 创建节点:createNode
  3. 增:insertHead、insertTail、insertPos
  4. 删:deleteByPos、deleteNodeByVal
  5. 改:modifyNodeByPos、modifyNodeByVal
  6. 查:findNodeByPos、findNodeByVal
  7. 遍历:printListTable
  8. 释放整个链表:deleteListTable
c 复制代码
#include <stdlib.h>
#include <stdio.h>

typedef struct ListTable {
	struct ListTable* next;
	int val;
};

ListTable* createNode(int val) {
	ListTable* node = (ListTable*)malloc(sizeof(ListTable));
	if (node == NULL) return NULL;
	node->next = NULL;
	node->val = val;
	return node;
}

// 《=========================增=========================》
// 头不存数据
bool insertHead(ListTable* head, int val) {
	if (!head) return false;
	ListTable* node = createNode(val);
	if (!node) return false;
	ListTable* p = head;
	ListTable* temp = NULL;
	temp = p->next;
	p->next = node;
	node->next = temp;
	return true;
}

bool insertTail(ListTable* head, int val) {
	if (!head) return false;
	ListTable* node = createNode(val);
	if (!node) return false;
	ListTable* p = head;
	while (p->next) {
		p = p->next;
	}
	p->next = node;
	return true;
}

bool insertPos(ListTable* head, int pos, int val) {
	if (!head || pos == 0) return false;
	ListTable* p = head;
	int count = 0;
	while (count != (pos - 1) || !p) {
		if (p->next)
			p = p->next;
		else
			break;
		++count;
	}
	if (count != (pos - 1)) return false;
	ListTable* node = createNode(val);
	if (!node) return false;
	ListTable* temp = p->next;
	p->next = node;
	node->next = temp;
	return true;
}

// 《=========================删=========================》
bool deleteByPos(ListTable* head, int pos) {
	if (!head || !head->next || pos == 0) return false;
	ListTable* p = head->next;
	ListTable* pre = head;
	int count = 1;
	while (p && count != pos) {
		if (!p->next) break;
		pre = pre->next;
		p = p->next;
		++count;
	}
	if (count != pos) return false;
	pre->next = p->next;
	free(p);
	return true;
}

bool deleteNodeByVal(ListTable* head, int val) {
	if (!head && !head->next) return false;
	ListTable* p = head->next;
	ListTable* pre = head;
	while (p) {
		if (p->val == val) {
			pre->next = p->next;
			free(p);
			p = pre->next;
			continue;
		}
		if (!p->next) break;
		pre = pre->next;
		p = p->next;
	}
	return true;
}

// 《=========================查=========================》
ListTable* findNodeByPos(ListTable* head, int pos) {
	if (!head) return NULL;
	ListTable* p = head;
	int count = 0;
	while (p && count != pos) {
		if (!p->next) break;
		p = p->next;
		++count;
	}
	if (count != pos) return NULL;
	return p;
}

ListTable* findNodeByVal(ListTable* head, int val) {
	if (!head) return NULL;
	ListTable* p = head;
	while (p) {
		if (p->val == val) return p;
		if (!p->next) break;
		p = p->next;
	}
	return NULL;
}

// 《=========================改=========================》
bool modifyNodeByPos(ListTable* head, int pos, int val) {
	if (!head || pos == 0) return false;
	ListTable* p = head;
	int count = 0;
	while (p && (count != pos)) {
		if (!p->next) break;
		p = p->next;
		++count;
	}
	if (count != pos) return false;
	p->val = val;
	return true;
}

bool modifyNodeByVal(ListTable* head, int src_val, int dst_val) {
	if (!head) return false;
	ListTable* p = head;
	while (p) {
		if (p->val == src_val) {
			p->val = dst_val;
		}
		p = p->next;
	}
	return true;
}

// 《=========================遍历=========================》
void printListTable(ListTable* head) {
	if (!head) return;
	ListTable* p = head;
	printf("遍历链表:");
	while (p) {
		printf("%d ", p->val);
		p = p->next;
	}
}

// 《=========================释放=========================》
void deleteListTable(ListTable* head) {
	if (!head) return;
	ListTable* temp = NULL;
	while (head) {
		temp = head->next;
		free(head);
		head = temp;
	}
}

2. 测试用例

c 复制代码
#include <stdlib.h>
#include <stdio.h>

typedef struct ListTable {
	struct ListTable* next;
	int val;
};

ListTable* createNode(int val) {
	ListTable* node = (ListTable*)malloc(sizeof(ListTable));
	if (node == NULL) return NULL;
	node->next = NULL;
	node->val = val;
	return node;
}

// 《=========================增=========================》
// 头不存数据
bool insertHead(ListTable* head, int val) {
	if (!head) return false;
	ListTable* node = createNode(val);
	if (!node) return false;
	ListTable* p = head;
	ListTable* temp = NULL;
	temp = p->next;
	p->next = node;
	node->next = temp;
	return true;
}

bool insertTail(ListTable* head, int val) {
	if (!head) return false;
	ListTable* node = createNode(val);
	if (!node) return false;
	ListTable* p = head;
	while (p->next) {
		p = p->next;
	}
	p->next = node;
	return true;
}

bool insertPos(ListTable* head, int pos, int val) {
	if (!head || pos == 0) return false;
	ListTable* p = head;
	int count = 0;
	while (count != (pos - 1) || !p) {
		if (p->next)
			p = p->next;
		else
			break;
		++count;
	}
	if (count != (pos - 1)) return false;
	ListTable* node = createNode(val);
	if (!node) return false;
	ListTable* temp = p->next;
	p->next = node;
	node->next = temp;
	return true;
}

// 《=========================删=========================》
bool deleteByPos(ListTable* head, int pos) {
	if (!head || !head->next || pos == 0) return false;
	ListTable* p = head->next;
	ListTable* pre = head;
	int count = 1;
	while (p && count != pos) {
		if (!p->next) break;
		pre = pre->next;
		p = p->next;
		++count;
	}
	if (count != pos) return false;
	pre->next = p->next;
	free(p);
	return true;
}

bool deleteNodeByVal(ListTable* head, int val) {
	if (!head && !head->next) return false;
	ListTable* p = head->next;
	ListTable* pre = head;
	while (p) {
		if (p->val == val) {
			pre->next = p->next;
			free(p);
			p = pre->next;
			continue;
		}
		if (!p->next) break;
		pre = pre->next;
		p = p->next;
	}
	return true;
}

// 《=========================查=========================》
ListTable* findNodeByPos(ListTable* head, int pos) {
	if (!head) return NULL;
	ListTable* p = head;
	int count = 0;
	while (p && count != pos) {
		if (!p->next) break;
		p = p->next;
		++count;
	}
	if (count != pos) return NULL;
	return p;
}

ListTable* findNodeByVal(ListTable* head, int val) {
	if (!head) return NULL;
	ListTable* p = head;
	while (p) {
		if (p->val == val) return p;
		if (!p->next) break;
		p = p->next;
	}
	return NULL;
}

// 《=========================改=========================》
bool modifyNodeByPos(ListTable* head, int pos, int val) {
	if (!head || pos == 0) return false;
	ListTable* p = head;
	int count = 0;
	while (p && (count != pos)) {
		if (!p->next) break;
		p = p->next;
		++count;
	}
	if (count != pos) return false;
	p->val = val;
	return true;
}

bool modifyNodeByVal(ListTable* head, int src_val, int dst_val) {
	if (!head) return false;
	ListTable* p = head;
	while (p) {
		if (p->val == src_val) {
			p->val = dst_val;
		}
		p = p->next;
	}
	return true;
}

// 《=========================遍历=========================》
void printListTable(ListTable* head) {
	if (!head) return;
	ListTable* p = head;
	printf("遍历链表:");
	while (p) {
		printf("%d ", p->val);
		p = p->next;
	}
}

// 《=========================释放=========================》
void deleteListTable(ListTable* head) {
	if (!head) return;
	ListTable* temp = NULL;
	while (head) {
		temp = head->next;
		free(head);
		head = temp;
	}
}

/* ================== 测试辅助 ================== */
#define ASSERT_TRUE(expr, msg) \
	do { if (!(expr)) { printf("[FAIL] %s (表达式: %s)\n", msg, #expr); ++failCount; } else { ++passCount; } } while(0)

static int passCount = 0;
static int failCount = 0;

int lengthWithoutDummy(ListTable* head) {
	if (!head) return 0;
	int len = -1; // 头结点不算数据
	ListTable* p = head;
	while (p) {
		++len;
		p = p->next;
	}
	return len < 0 ? 0 : len;
}

int getValueAt(ListTable* head, int pos) { // pos 从 1 开始(跳过头结点)
	if (!head || pos <= 0) return -99999;
	ListTable* p = head->next;
	int idx = 1;
	while (p && idx < pos) {
		p = p->next;
		++idx;
	}
	return (p && idx == pos) ? p->val : -99999;
}

void rebuild(ListTable** headPtr) {
	deleteListTable(*headPtr);
	*headPtr = createNode(0); // dummy
}

/* =============== MAIN: 综合测试用例 =============== */
int main(void) {
	printf("开始链表单元测试...\n");

	ListTable* head = createNode(0);
	ASSERT_TRUE(head != NULL, "创建头结点");

	// 1. 头插测试
	for (int i = 1; i <= 5; ++i) {
		ASSERT_TRUE(insertHead(head, i), "insertHead 成功");
	}
	ASSERT_TRUE(lengthWithoutDummy(head) == 5, "头插后长度=5");
	ASSERT_TRUE(getValueAt(head, 1) == 5, "头插后第1个元素=5");
	ASSERT_TRUE(getValueAt(head, 5) == 1, "头插后第5个元素=1");

	// 2. 尾插测试
	for (int i = 10; i <= 13; ++i) {
		ASSERT_TRUE(insertTail(head, i), "insertTail 成功");
	}
	ASSERT_TRUE(lengthWithoutDummy(head) == 9, "头+尾插后长度=9");
	ASSERT_TRUE(getValueAt(head, 9) == 13, "最后一个元素=13");

	printListTable(head);

	// 3. 按位置插入(有效位置)
	ASSERT_TRUE(insertPos(head, 1, 100), "位置1插入 100");
	ASSERT_TRUE(getValueAt(head, 1) == 100, "位置1元素=100");
	ASSERT_TRUE(insertPos(head, 5, 200), "位置5插入 200");
	ASSERT_TRUE(getValueAt(head, 5) == 200, "位置5元素=200");

	// 4. 按位置插入(非法位置)
	ASSERT_TRUE(!insertPos(head, 999, 300), "非法位置插入失败");

	printListTable(head);

	// 5. 按位置修改
	ASSERT_TRUE(modifyNodeByPos(head, 1, 101), "修改位置1为101");
	ASSERT_TRUE(getValueAt(head, 1) == 101, "验证修改位置1=101");

	// 6. 按值批量修改(将所有 10 改为 88)
	ASSERT_TRUE(modifyNodeByVal(head, 10, 88), "按值修改 10->88");
	ListTable* found10 = findNodeByVal(head, 10);
	ASSERT_TRUE(found10 == NULL, "值10已全部替换");
	ASSERT_TRUE(findNodeByVal(head, 88) != NULL, "找到替换后的 88");

	// 7. 查找(按位置 / 按值)
	ListTable* nodePos5 = findNodeByPos(head, 5);
	ASSERT_TRUE(nodePos5 != NULL, "findNodeByPos(5) 存在");
	ListTable* nodeVal200 = findNodeByVal(head, 200);
	ASSERT_TRUE(nodeVal200 != NULL && nodeVal200->val == 200, "findNodeByVal(200) 找到");

	// 8. 删除指定位置
	int beforeLen = lengthWithoutDummy(head);
	ASSERT_TRUE(deleteByPos(head, 5), "删除位置5");
	ASSERT_TRUE(lengthWithoutDummy(head) == beforeLen - 1, "长度减少1");
	ASSERT_TRUE(getValueAt(head, 5) != 200, "原位置5的200被删除");

	// 9. 删除指定值(删除所有 88)
	ASSERT_TRUE(deleteNodeByVal(head, 88), "删除值 88");
	ASSERT_TRUE(findNodeByVal(head, 88) == NULL, "88 不再存在");

	printListTable(head);

	// 10. 边界:删除不存在位置
	ASSERT_TRUE(!deleteByPos(head, 999), "删除不存在位置失败");

	// 11. 重建 + 空链表操作
	rebuild(&head);
	ASSERT_TRUE(lengthWithoutDummy(head) == 0, "重建后长度=0");
	ASSERT_TRUE(findNodeByPos(head, 1) == NULL, "空链表 findNodeByPos(1)=NULL");
	ASSERT_TRUE(!deleteByPos(head, 1), "空链表 deleteByPos(1) 失败");
	ASSERT_TRUE(modifyNodeByVal(head, 1, 2), "空链表按值修改安全返回");

	// 12. 单元素删除
	ASSERT_TRUE(insertTail(head, 555), "插入单元素 555");
	ASSERT_TRUE(lengthWithoutDummy(head) == 1, "长度=1");
	ASSERT_TRUE(deleteByPos(head, 1), "删除唯一元素");
	ASSERT_TRUE(lengthWithoutDummy(head) == 0, "删除后长度=0");
	ASSERT_TRUE(findNodeByVal(head, 555) == NULL, "值555不存在");

	deleteListTable(head);
	head = NULL;

	printf("\n测试结束: 通过 %d 项, 失败 %d 项\n", passCount, failCount);
	if (failCount == 0) {
		printf("所有测试通过。\n");
	}
	else {
		printf("存在失败,请检查实现。\n");
	}
	return failCount == 0 ? 0 : 1;
}
相关推荐
靠沿3 小时前
Java数据结构初阶——LinkedList
java·开发语言·数据结构
Elias不吃糖3 小时前
LeetCode每日一练(209, 167)
数据结构·c++·算法·leetcode
Want5953 小时前
C/C++跳动的爱心②
c语言·开发语言·c++
初晴や3 小时前
指针函数:从入门到精通
开发语言·c++
悦悦子a啊4 小时前
项目案例作业(选做):使用文件改造已有信息系统
java·开发语言·算法
小殊小殊4 小时前
【论文笔记】知识蒸馏的全面综述
人工智能·算法·机器学习
无限进步_4 小时前
C语言动态内存管理:掌握malloc、calloc、realloc和free的实战应用
c语言·开发语言·c++·git·算法·github·visual studio
hweiyu004 小时前
数据结构:循环链表
数据结构·链表
im_AMBER4 小时前
AI井字棋项目开发笔记
前端·笔记·学习·算法