代码实现
由于手动分配内存太麻烦, 我就写了两个函数模仿其他语言new的用法
#include <stdio.h>
#include <stdlib.h>
/**
* 链表元素
*/
typedef struct node {
int data; // 元素值
struct node *next; // 指向下个元素
} Node;
/**
* 链表
*/
typedef struct linklist {
int length; // 链表长度
Node *head; // 带头节点
Node *tail; // 尾结点,通过这个节点可以使插入的时间复杂度变为O(1)
} LinkList;
// 打印链表
void printAll(const LinkList *l);
// 插入元素,尾部插入
void insert(LinkList *l, int data);
// 按索引删除元素
int delete(LinkList *l, int index);
// 按值删除匹配的第一个元素
int deleteByValue(LinkList *l, int data);
// 按值删除所有匹配的元素
int deleteAllByValue(LinkList *l, int value);
// 按索引更新元素
int update(LinkList *l, int index, int value);
// 按索引获取元素
int get(const LinkList *l, int index);
// 清空链表, 不会删除带头节点
int clear(LinkList *l);
// 销毁链表, 释放所有内存
void destory(LinkList *l); // 销毁链表
// 分配并创建链表
LinkList *newLinkList(void);
// 分配并创建链表元素
Node *newNode(int data, Node *next);
int main()
{
LinkList *l = newLinkList();
// 添加元素
insert(l, 1);
insert(l, 2);
insert(l, 3);
insert(l, 4);
insert(l, 4);
insert(l, 4);
insert(l, 4);
insert(l, 5);
// 元素删除
delete(l, 1);
deleteByValue(l, 2);
deleteAllByValue(l, 4);
// 更新
update(l, 2, 6);
// 打印
printAll(l);
// 获取元素
printf("第2个元素的值为:%d\n", get(l, 2));
// 清空链表
clear(l);
// 清空之后再打印
printAll(l);
// 销毁
destory(l);
return 0;
}
/**
* 手动创建一个new 函数来创建链表
*/
LinkList *newLinkList(void)
{
LinkList *l = (LinkList *)malloc(sizeof(LinkList));
l->length = 0;
l->head = newNode(0, NULL);
l->tail = l->head;
return l;
}
/**
* 手动创建一个new 函数来创建元素
*/
Node *newNode(int data, Node *next)
{
Node *n = (Node *)malloc(sizeof(Node));
n->data = data;
n->next = next;
return n;
}
/**
* 插入一个新元素, 尾部插入
*/
void insert(LinkList *l, int data)
{
// 创建一个新的元素
Node *latestNode = newNode(data, l->tail->next);
// 将新元素放在最后一个元素之后
l->tail->next = latestNode;
// 将尾结点指向最后一个元素
l->tail = latestNode;
// 更新链表长度
l->length++;
}
/**
* 打印链表
*/
void printAll(const LinkList *l)
{
printf("\n开始打印链表。。。\n");
int i = 1;
if (l->length > 0) {
// 忽略带头结点r
Node *temp = l->head->next;
while (temp != NULL)
{
printf(" ->第%d个元素的值为: %d\n", i, temp->data);
i++;
temp = temp->next;
}
}
printf("结束打印链表。。。\n\n");
}
/**
* 根据索引删除元素, 查到到上一个索引, 将上一个索引指向下下个元素即可
*/
int delete(LinkList *l, int index)
{
if (index > l->length || index < 1) {
return 0;
}
int i = 1;
Node *temp = l->head; // 带头节点, 指向要删除的元素前一个节点
while (i != index)
{
temp = temp->next;
i++;
}
Node *item = temp->next; // 先保存要删除的节点
temp->next = temp->next->next; // 更新上个节点指向下下个节点
free(item);
return 1;
}
/**
* 按值删除第一个匹配的元素
*/
int deleteByValue(LinkList *l, int value)
{
if (l->length < 1) {
return 0;
}
Node *temp, *item;
temp = l->head;
// 查找要删除的第一个元素, 如果查找到最后一个元素(最后一个元素next指向NULL), 说明没有该值
while (temp->next != NULL && temp->next->data != value)
{
temp = temp->next;
}
// 查找到了元素
if (temp->next != NULL) {
item = temp->next; // 要删除的元素
temp->next = temp->next->next; // 指向下下个元素
free(item); // 释放要删除的元素
l->length--; // 更新链表长度
return 1;
}
return 0;
}
/**
* 按值删除所有匹配的元素
*/
int deleteAllByValue(LinkList *l, int value)
{
if (l->length < 1) {
return 0;
}
Node *temp, *item;
temp = l->head;
while (temp != NULL && temp->next != NULL)
{
if (temp->next->data == value) {
item = temp->next;
temp->next = temp->next->next; // 将指针指向下下个元素, 不能移动指针到下下个元素, 如果下下个元素也是要删除的元素,将会出现内存溢出和遗漏
free(item);
l->length--;
} else {
temp = temp->next;
}
}
return 1;
}
/**
* 按索引更新元素
*/
int update(LinkList *l, int index, int value)
{
if (index > l->length || l->length < 1) {
return 0;
}
Node *temp = l->head;
// 找到要修改的节点
// 第0次, 指向第一个节点
// 。。。, 所以index-1个节点就是我们要修改的节点
for (int i = 0; i < index; i++)
{
temp = temp->next;
}
temp->data = value;
return 1;
}
/**
* 按索引获取元素
*/
int get(const LinkList *l, int index)
{
if (index > l->length || l->length < 1) {
return -1;
}
Node *temp = l->head;
for (int i = 0; i < index; i++)
{
temp = temp->next;
}
return temp->data;
}
/**
* 清空链表元素,仅保留头结点和尾结点
*/
int clear(LinkList *l)
{
if (l->length <= 0) {
return 0;
}
// 从第一个元素开始删除,保留头节点
Node *temp = l->head->next;
while (temp != NULL)
{
l->tail = temp->next; // 存储下个节点的指针
free(temp); // 释放当前节点
temp = l->tail; // 重新指向下个节点
}
l->tail = l->head; // 修复尾结点指向头结点
l->length = 0; // 重置长度
return 1;
}
/**
* 销毁链表
*/
void destory(LinkList *l)
{
clear(l); // 先清空元素
free(l->head); //释放头结点
free(l);
l = NULL; // 将链表指向NULL
}
输出结果
shantong@mac# gcc ./linklist.c && ./a.out
开始打印链表。。。
->第1个元素的值为: 3
->第2个元素的值为: 6
结束打印链表。。。
第2个元素的值为:6
开始打印链表。。。
结束打印链表。。。