链表
一、什么是链表
链表是数据结构中线性表的一种,其中每个元素实际上是一个单独的结构体对象,二所有对象都通过每个元素中的指针链接在一起。它是以结构体为节点,将一个结构体看成数据域和指针两个部分,数据域用于存储数据,指针域用于链接下一个节点。
二、链表的特点
1、没有固定产大姑,可以自由增加节点
2、链表能够实现快速插入删除数据
3、与数组相似,链表也是一种现象数据结构
4、链表的未借点的后续必定指向空。
链表和数据的区别:数组是顺序存储的,而链表是链式存储的。
单链表
单链表结构体的声明
typedef int Type;//数据类型通过typedef取别名的形式来进行灵活使用
struct Node{//单链表节点结构体声明
Type data;//链表节点的数据域,用于存储数据
structNode *next;//链表节点的指针域,用于指向下一个节点
};
struct LinkList{//单链表结构体的声明
struct Node *head;//链表头结点的指针域,用于指向链表都开头
struct Node *next;//链表尾节点的指针域,用于指向链表都末尾
int lenth;//链表的长度
};
链表的功能实现
1.单链表的创建
LL* list_init()
{
LL* temp = (LL*)malloc(sizeof(LL));
if (NULL == temp)
{//如果动态开辟内存失败,temp指针指向了NULL
printf("单链表创建失败!");
return NULL;
}
temp->head = NULL;//单链表头节点指针置空
temp->end = NULL;//单链表尾指针置空
temp->lenth = 0;
return temp;
}
2.单链表的节点的连接
3.单链表的输出
void list_print(LL* list)
{
if (NULL == list)
{//如果整个链表不存在
printf("单链表不存在,数据输出失败!\n");
return;
}
if (NULL == list->head)
{//如果链表为空
printf("单链表没有数据,数据输出失败!\n");
return;
}
for (Node* temp = list->head; temp != NULL; temp = temp->next)
{
printf("%d", temp->data);
}
puts("NULL\n");
}
4.单链表的节点的插入
void list_insert_end(LL* list, Type val)//尾插法
{
if (NULL == list)
{//如果整个链表不存在,数据插入失败
printf("单链表创建失败!\n");
return;
}
if (NULL == list->head)//单链表为空创建第一个节点
{
/*Node* New = (Node*)malloc(sizeof(Node));
New->data = val;
list->head = New;
list->end = New;
New->next = NULL;*/
list->head = list->end = node_init(val);
list->lenth++;
}
else//如果创建的不是第一个节点,需要将新节点连接上链表上一个节点并将尾指针改变指向
{
/*Node* New = (Node*)malloc(sizeof(Node));
New->data = val;
list->end->next = New;//新节点接上链表尾部(前后节点之间建立连接)
list->end = New;//新节点成为新的尾部
New->next = NULL;*/
//创建一个 新节点连接上链表尾部
list->end = list->end->next= node_init(val);//新节点成为新的尾部(从右往左算)
list->lenth++;
}
}
5.单链表节点的删除
Type list_delete_Node(LL* list, int index)
{
if (NULL == list)
{//如果整个链表不存在,数据删除失败
printf("单链表删除失败!\n");
return;
}
if (NULL == list->head)
{//如果链表为空
printf("单链表没有数据,数据删除失败!\n");
return;
}
if (index <= 0 || index >= list->lenth + 1)
{
printf("数据输入位置错误!\n");
return;
}
if (1 == index)
{//删除头部节点
Node* temp = list->head;
list->head = list->head->next;//记录被删除节点的位置
Type val = temp->data;//记录被删除节点的数据
free(temp);
list->lenth--;
return val;
}
if (index == list->lenth)
{//删除尾部节点
Node* temp = list->end;
for (int i = 1; i < index - 1; i++)
{//找到删除位置的前一个节点
temp = temp->next;
}
Type val = list->end->data;//记录尾部节点数据
free(list->end);
list->end = temp;
return val;
}
//删除中间节点
//找到删除位置
Node* temp1 = list->head;
for (int i = 1; i < index - 1; i++)
{//找到删除位置的前一个节点
temp1 = temp1->next;
}
Node* temp2 = temp1->next;//指向被删除的节点
Type val = temp2->data;//指向被删除节点的数据
temp1->next = temp2->next;//删除位置的前一个节点的指针域跳过被删除位置的节点,指向下一个节点
free(temp2);//释放掉被删除节点的内存
}
6.向单边表指定位置插入数据
void list_insert(LL* list, int index, Type val)
{
if (NULL == list)
{//如果整个链表不存在,数据插入失败
printf("单链表创建失败!\n");
return;
}
if (index <= 0 || index >= list->lenth + 1)
{
printf("数据输入位置错误!\n");
return ;
}
Node* temp = list->head;
for (int i = 1; i < index-1; i++)
{//找到插入位置的前一个节点
temp = temp->next;
}
//有两种特殊情况,在头部和尾部插入
//在头节点之前插入
if (1 == index)
{//如果插入位置是第一个
Node* New = node_init(val);//创建新节点
New->next = list->head;
list->head = New;//新节点成为新的头节点
list->lenth++;
return;
}
//在尾节点之后插入
if (list->lenth + 1 == index)
{//如果插入位置刚好比链表长度大一个(在链表尾部之后插入新数据)
list->end = list->end->next = node_init(val);
list->lenth++;
return;
}
//中间节点的插入
Node* New = node_init(val);//创建新节点
New->next = temp->next;//新节点连接插入位置之后的节点
temp->next = New;//链表插入位置之前的节点连接上新节点
list->lenth++;
}