这里借用百度百科的概念:
单向链表(单链表)是链表的一种,其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始;链表是使用指针进行构造的列表;又称为结点列表,因为链表是由一个个结点组装起来的;其中每个结点都有指针成员变量指向列表中的下一个结点;
通过加粗的字体可以看出单向链表有以下特点
1. 链接方向是单向的
2. 顺序读取从头部开始
3. 链表是由一个个结点组装起来的
4. 每个结点都有指针成员变量指向列表中的下一个结点
由一张图简单说明:
head就是头部,也称为头节点。next1、next2、next3都是新建节点。由头节点和新建节点链接起来的就成为了一个单向链表。
每个节点包括头节点就是一块内存空间,这块内存空间存储着目标数据和下一个节点的地址。(如图所示)
总而言之,链表存储数据不是顺序的,不像顺序表一样是地址连续的数组。而是通过记录节点地址的方式将分散的数据域串连起来。
链表的作用也就是数据存储,数据存储就离不开数据的增、删、改、查。
下面实现数据的增、删、改、查
- 增(增加头节点,增加新节点)
typedef struct list_node//节点结构体
{
int date;//数据域,即地址指向的数据内容
struct list_node *next;//指针域,即内存地址
}LIST_NODE,*LIST_NODE_P;
//创建头节点
LIST_NODE_P create_head_node()
{
//申请头节点内存
LIST_NODE_P head_node = calloc(1, sizeof(LIST_NODE));
if (head_node == NULL)
{
perror("head_node memory request failed!\n");
}
//初始化
head_node->date = 0;
head_node->next = NULL;
//返回头节点地址
return head_node;
}
//新建节点
LIST_NODE_P create_new_node(LIST_NODE_P head, int num)
{
//申请新节点内存
LIST_NODE_P new_node = calloc(1, sizeof(LIST_NODE));
if (new_node == NULL)
{
perror("new_node memory request failed!\n");
return NULL;
}
//初始化数据域
new_node->date = num;
//初始化指针域
new_node->next = NULL;
return new_node;
}
//尾插法
bool tail_insert(LIST_NODE_P head, LIST_NODE_P new_node)
{
if (head == NULL)
{
perror("head_node memory receive failed!\n");
return false;
}
if (new_node == NULL)
{
perror("new_node memory receive failed!\n");
return false;
}
LIST_NODE_P p = head;
while (p->next != NULL)
{
p = p->next;
}
p->next = new_node;
return true;
}
- 查找数据
//查找数据
LIST_NODE_P Fine_Object(LIST_NODE_P head, int num)
{
if (head == NULL)
{
perror("head_node memory receive failed!\n");
return false;
}
LIST_NODE_P p = head;
for (p = head->next; p != NULL; p = p->next)
{
if (p->date == num)
{
printf("%d\n",p->date);
return p;
}
}
}
- 删除数据
//删除数据
bool Delete_Object(LIST_NODE_P head,int num)
{
if (head == NULL)
{
perror("head_node memory receive failed!\n");
return false;
}
LIST_NODE_P p = NULL;
LIST_NODE_P pos = NULL;
for (pos = head, p = head->next; p != NULL; pos = pos->next, p = p->next)
{
if(p->date == num)
{
//把前一个节点的next指向下一个节点
pos->next = p->next;
//把节点断开链接
p->next = NULL;
//释放节点内存
free(p);
return true;
}
}
return true;
}
- 修改数据
//修改数据
bool Change_Object(LIST_NODE_P node, int date)
{
if (node == NULL)
{
perror("new_node memory receive failed!\n");
return false;
}
node->date = date;
return true;
}