单向链表的实现,主要对链表进行CURD,由于是逻辑练习代码,所以实现删除、插入和查找功能的时候,传进去的是一个当作数组下标使用的整数。
主要难度在于链表逆转(要是双向的话就不用这么麻烦了,感觉又是一个典型的时间换空间例子),感觉逆转函数写得较为啰嗦和繁琐,效率较低,注释也不知道怎么写好(表达能力渣)。
插入和删除节点的代码有重复,本该抽象成一个函数了,但我实在懒,还是算了。
#include <stdio.h>
#include <stdlib.h>
//定义节点的数据类型
typedef struct _node
{
int data;
struct _node* p_next;
}Node;
//定义单链表的数据类型
typedef struct _list
{
//头指针,记录第一个元素
Node* p_head;
//尾指针,最后一个元素
Node* p_end;
int size;
}List;
//创建一个链表
void create_list(List** pp_list);
//创建一个节点
Node* create_node(int data);
//向链表头节点位置插入新节点
void push_head(List* p_list, int data);
//遍历链表中的所有元素
void travel(List* p_list);
//链表逆序
void reverse_list(List* P_list);
//计算链表中元素的个数
int size(List* p_list);
//清空链表中所有的节点
void clear(List* p_list);
//向指定的下标位置插入指定的节点,下标从0开始
void insert(List* p_list, int pos, int data);
//实现删除指定下标位置的节点操作
void del(List* p_list, int pos);
//删除头节点的功能
void pop_head(List* p_list);
//删除尾节点的功能
void pop_tail(List* p_list);
//判断链表是否为空
int empty(List* p_list);
//判断链表是否为满
int full(List* p_list);
//取得头节点的元素值
int get_head(List* p_list);
//取得尾节点的元素值
int get_tail(List* p_list);
//测试代码
int main(void)
{
List* p_list = NULL;
create_list(&p_list);
int i = 0;
while (i < 5)
{
push_head(p_list, i++);
}
travel(p_list);
printf("%d\n", size(p_list));
//clear(p_list);
//printf("%d\n", size(p_list));
insert(p_list, 2, 111);
insert(p_list, 0, 222);
insert(p_list, 7, 333);
travel(p_list);
printf("------------------------------------------------------------\n");
del(p_list, 7);
travel(p_list);
printf("尾指针等于 %d\n", p_list->p_end->data);
del(p_list, 5);
travel(p_list);
printf("尾指针等于 %d\n", p_list->p_end->data);
del(p_list, 5);
travel(p_list);
printf("尾指针等于 %d\n", p_list->p_end->data);
del(p_list, 4);
travel(p_list);
printf("尾指针等于 %d\n", p_list->p_end->data);
return 0;
}
/*
函数名:reverse_list
功 能:链表逆序
参 数:需要逆序的链表
*/
void reverse_list(List* p_list)
{
Node* next = null;
Node* prev = null;
Node* head = p_list->p_head;
while(head != NULL)
{
next = head->next;
head->next = prev;
prev = head;
head = next;
}
}
//向链表头节点位置插入新节点
void push_head(List* p_list, int data)
{
//创建新节点
Node *p_node = create_node(data);
if (NULL == p_list->p_head)
{
p_list->p_end = p_node;
}
//将新节点插入到头节点位置
p_node->p_next = p_list->p_head;
p_list->p_head = p_node;
p_list->size++;
}
//遍历链表中的所有元素
void travel(List* p_list)
{
Node *p_node = p_list->p_head;
while (NULL != p_node)
{
printf("%d ", p_node->data);
p_node = p_node->p_next;
}
printf("\n");
}
//创建一个链表
void create_list(List** pp_list)
{
*pp_list = (List*)malloc(sizeof(List));
(*pp_list)->p_head = NULL;
(*pp_list)->p_end = NULL;
(*pp_list)->size = 0;
}
//创建一个节点
Node* create_node(int data)
{
Node* p_node = (Node*)malloc(sizeof(Node));
p_node->p_next = NULL;
p_node->data = data;
}
//计算链表中元素的个数
int size(List* p_list)
{
return p_list->size;
}
//清空链表中所有的节点
void clear(List* p_list)
{
Node *p_temp = NULL;
while(NULL != p_list->p_head)
{
p_temp = p_list->p_head;
p_list->p_head = p_list->p_head->p_next;
free(p_temp);
p_temp = NULL;
}
p_list->size = 0;
}
//向指定的下标位置插入指定的节点,下标从0开始
void insert(List* p_list, int pos, int data)
{
if (pos < 0 || size(p_list) < pos)
{
printf("插入的节点的坐标不合法\n");
return;
}
//创建一个新节点
Node* p_node = create_node(data);
if (0 == pos)
{
p_node->p_next = p_list->p_head;
p_list->p_head = p_node;
p_list->size++;
p_list->p_end = p_node;
return;
}
Node* p_temp = p_list->p_head;
int i = 0;
for (i = 0; i < pos - 1; i++)
{
p_temp = p_temp->p_next;
}
p_node->p_next = p_temp->p_next;
p_temp->p_next = p_node;
if (NULL == p_node->p_next)
{
p_list->p_end = p_node;
}
p_list->size++;
}
//实现删除指定下标位置的节点操作
void del(List* p_list, int pos)
{
//判断删除的坐标是否合法以及链表是否为空
if (pos < 0 || pos >= size(p_list))
{
printf("坐标不合法, 删除失败\n");
return;
}
//当删除头节点时的处理方式
Node *p_node = p_list->p_head;
if (0 == pos)
{
p_list->p_head = p_node->p_next;
free(p_node);
p_list->size--;
return;
}
//当删除其它位置节点时的处理方式
int i = 0;
//找出要删除的下标的前一个元素
for (i = 0; i < pos - 1; i++)
{
p_node = p_node->p_next;
}
//记录要摧毁的节点的下一个节点
Node *temp = p_node->p_next->p_next;
free(p_node->p_next);
//指向摧毁了的节点的下一个节点
p_node->p_next = temp;
//如果删除的元素是最后一个元素,改变尾指针的指向
if (NULL == p_node->p_next)
{
p_list->p_end = p_node;
}
p_list->size--;
}
//删除头节点的功能
void pop_head(List* p_list)
{
del(p_list, 0);
}
//删除尾节点的功能
void pop_tail(List* p_list)
{
del(p_list, p_list->size - 1);
}
//判断链表是否为空
int empty(List* p_list)
{
return 0 == p_list->size;
}
//判断链表是否为满
int full(List* p_list)
{
return 0;
}
//取得头节点的元素值
int get_head(List* p_list)
{
return p_list->p_head->data;
}
//取得尾节点的元素值
int get_tail(List* p_list)
{
return p_list->p_end->data;
}