一、链表简介
1、链表是物理存储单元上非连续的、非顺序的存储结构,数据元素的逻辑顺序是通过链表的指针地址实现,有一系列结点(地址)组成,结点可动态的生成。
2、结点包括两个部分:(1)存储数据元素的数据域(内存空间),(2)存储指向下一个结点地址的指针域。类似如下:
二、链表和数组的区别
参考博客:链表(图文详解)_糊涂糖僧的博客-优快云博客_链表
1、数组静态分配内存,链表动态分配内存。故链表内存利用率高,不会浪费内存,可以使用内存中细小的不连续的空间,只有在需要的时候才去创建空间。大小不固定,拓展很灵活。
2、数组在内存中是连续的,链表是不连续的。
3、数组利用下标定位,查找的时间复杂度是O(1),链表通过遍历定位元素,查找的时间复杂度是O(N)。
4、数组插入和删除需要移动其他元素,时间复杂度是O(N),链表的插入或删除不需要移动其他元素,时间复杂度是O(1)。
数组优点:
1、随机访问性比较强,可以通过下标进行快速定位。
2、查找速度快
数组缺点:
1、插入和删除的效率低,需要移动其他元素。
2、会造成内存的浪费,因为内存是连续的,所以在申请数组的时候就必须规定七内存的大小,如果不合适,就会造成内存的浪费。
3、内存空间要求高,创建一个数组,必须要有足够的连续内存空间。
4、数组的大小是固定的,在创建数组的时候就已经规定好,不能动态拓展。
链表优点:
1、插入和删除的效率高,只需要改变指针的指向就可以进行插入和删除。
2、内存利用率高,不会浪费内存,可以使用内存中细小的不连续的空间,只有在需要的时候才去创建空间。大小不固定,拓展很灵活。
链表缺点:
查找的效率低,因为链表是从第一个节点向后遍历查找。
三、单链表操作
参考博客:什么是链表?(图解)_十二匹的博客-优快云博客_什么是链表
单链表例:
1、链表结构体
struct node
{
int data; //存放数据
struct node *next; //存放下一个节点地址
};
2、头尾节点
//开头定义为全局变量即可
struct node *head = NULL; // 头节点
struct node *end = NULL; // 尾节点
3、创建节点
struct node *creat_node(int data)
{
struct node *new = malloc(sizeof(struct node));
new->data = data;
new->next = NULL;
if (head == NULL) //链表为空
{
head = new;
end = new;
}
return new; //返回节点指针
}
4、按顺序插入节点 (链接节点)
struct node *insert_node(struct node *old,struct node *new)
{
old->next = new; //链接节点
end = new; //尾指针赋值
}
5、通过index查找节点
struct node *find_node(struct node *linklist,int index)
{
int current_index = 1;
if (linklist == NULL)
{
printf("链表为空!\n");
return NULL;
}
while (linklist != NULL)
{
if (index == current_index)
{
return linklist;
}
linklist = linklist->next;
current_index++;
}
return NULL;
}
6、通过数据查找节点
struct node *find_node_position(struct node *linklist,int data)
{
int position=1;
if (linklist == NULL)
{
printf("链表为空!\n");
return NULL;
}
while (linklist != NULL)
{
if ( data == linklist->data )
{
//printf("data %d position=%d\n",linklist->data,position);
return linklist;
}
linklist = linklist->next;
position++;
}
return NULL;
}
7、指定位置后一位插入节点
void insert_node_purpose(struct node *linklist,int index, int data)
{
struct node *temp = creat_node(data);
struct node *find = find_node(linklist,index);
if (linklist == NULL)
{
printf("链表为空!\n");
return;
}
else if (find == NULL)
{
printf("无此节点!\n");
return;
}
else
{
// 将新节点的next 设置为 当前插入位置节点 的 下一个节点
temp->next = find->next;
// 将 当前插入位置节点的next 设置为新节点
find->next = temp;
}
}
8、改指定节点数据
void set_node(struct node *linklist, int index, int data)
{
struct node *find = find_node(linklist,index); // 查找节点
if (find == NULL)
{
printf("无此节点!\n");
return;
}
find->data = data;
}
9、通过index删除指定节点
void delete_node(struct node *linklist,int index)
{
struct node *find = find_node(linklist,index); // 查找节点
if (find == NULL) // 无此节点
{
printf("index error,can't find the node\n");
return ;
}
else
{
struct node *node = head;
if (head == end) // 只有一个节点
{
free(head);
head = NULL;
end = NULL;
}
else // 大于一个节点
{
if (find == head) // 删除头节点
{
struct node *old = head; // 暂存旧节点
head = head->next; // 将第二个节点设置为新头节点
free(old); // 释放头旧节点的内存
}
else if (find == end) // 删除尾节点
{
while (node->next != find) // 找到要删除的节点
{
node = node->next;
}
// 将倒数第二个节点的next置为NULL后就相当于设置为尾节点
node->next = NULL;
end = node; //将倒数第二个节点设置为尾节点
free(find); //释放被删节点的内存
}
else // 删除中间个某节点,和删除尾节点类似
{
while (node->next != find) // 找到要删除的节点
{
node = node->next;
}
// 将被删节点的上一个节点的next设置为被删节点的下一个节点
node->next = find->next;
free(find); //释放被删节点的内存
}
}
}
printf("index %d has deleted!\n", index);
}
10、删除整个链表
void delete_list(struct node *linklist)
{
struct node *node = head;
if (linklist == NULL)
{
printf("链表为空!\n");
return;
}
while (linklist != NULL)
{
struct node *old = linklist; //暂存旧节点
linklist = linklist->next;
free(old);
}
head = NULL;
end = NULL;
printf("Delete linklist successfully!\n", __FUNCTION__);
}
11、显示节点数据 (遍历节点)
void show(struct node *linklist)
{
while(1)
{
if(linklist == NULL) //假设链表已经为NULL则返回
{
return ;
}
printf("linklist=%d\n",linklist->data);
linklist = linklist->next; //遍历节点,指向下一个节点
}
}
四、测试代码
main:
int main(int argc, char *argv[])
{
struct node *a0 = creat_node(10);
struct node *a1 = creat_node(20);
struct node *a2 = creat_node(30);
insert_node(a0,a1);
insert_node(a1,a2);
show(a0);
printf("head=%d\n",head->data);
printf("end=%d\n\n",end->data);
/* 在20后插入25 */
printf("在20后插入25:\n");
insert_node_purpose(a0,2,25);
show(a0);
printf("\n");
/* 把20改为15 */
printf("把20改为15:\n");
set_node(a0,2,15);
show(a0);
printf("\n");
/* 删除15 */
printf("删除15:\n");
delete_node(a0,2);
show(a0);
printf("\n");
return 0;
}
结果: