单链表
//单链表属于线性表
一、单链表的概念
单链表是什么?
链表是数据结构中线性表的一种,其中的每个元素实际上是一个单独的结构体对象,而所有对象都通过每个元素中的指针链接在一起。它是以结构体为节点,将一个结构体看成数据域和指针域两个部分,数据域用于存储数据,指针域用于连接下一个节点。链表中每个结构体对象叫做节点,其中第一个数据节点叫做链表的首元节点;如果第一个节点不用于存储数据,只用于代表链表的起始点,则这个节点称为链表的头节点。
单链表的特点:
1、单链表没有固定的长度,可以自由增加节点。 2、单链表能够实现快速的插入删除数据。 3、与数组类似,单链表也是一种线性数据结构。 4、单链表的尾结点的后继必定指向空。 单链表和数组的区别:数组是顺序存储的,而单链表是链式存储的。
单链表的节点类型
//结构体类型:单链表节点的类型
struct node
{
int id;//节点要保存的数据
struct node*next;//指针成员:指向下一个节点
};
二、单链表的初始化
//初始化单链表
//申请一个头节点:让head指向这个节点
//头节点:不保存数据,单链表开头的标志
struct node* init()
{
//temp是一个临时指针变量:保存从堆区申请的内存首地址
struct node*temp = (struct node*)malloc(sizeof(struct node));
temp->id = 0;
temp->next = NULL;
return temp;
}
三、单链表元素的增加
//头插法三步骤
//1、申请新节点,把数据放进这个新节点S
//2、新节点S指针域保存头节点的下一个节点的地址
//3、头节点指针保存新节点S的地址
void insert(struct node*head,int data)//data:要增加的元素值
{
//1、申请新节点,把数据放进这个新节点S
struct node*S = (struct node*)malloc(sizeof(struct node));
S->id = data; //新节点保存要增加的元素值
//2、新节点S指针域保存头节点的下一个节点的地址
S->next = head->next;
//3、头节点指针保存新节点S的地址
head->next = S;
}
//尾插法
//1、定义一个指针变量P,P用来保存当前单链表中的最后一个节点的地址
//2、定义一个指针变量S,申请一个新的节点(保存要增加的数据),生成新节点S
//3、新节点S指针为空,节点P的指针域指向新节点S
void insertEnd(struct node*head, int data)
{
//1、定义一个指针变量P,P用来保存当前单链表中的最后一个节点的地址
struct node*p = head;
while (p->next != NULL)//P不是单链表中最后一个节点
{
//p++;//不可以的,因为内存 不连续
p = p->next;//p指向下一个节点
}
//循环执行完之后,p指向单链表中的最后一个节点
//2、定义一个指针变量S,申请一个新的节点(保存要增加的数据),生成新节点S
struct node*S = (struct node*)malloc(sizeof(struct node));
S->id = data; //新节点保存要增加的元素值
//3、新节点S指针为空,节点P的指针域指向新节点S
S->next = p->next;
p->next = S;
}
四、输出单链表中的所有元素
void print(struct node*head)
{
if (head == NULL)
{
printf("单链表不存在\n\n");
return;
}
struct node*p = head->next;
while (p != NULL)//是p指向下一个节点,当p是最后一个节点之后的NULL,结束循环
{
printf("%d --> ", p->id);
p = p->next;
}
printf("NULL\n\n");
}
五、单链表元素的删除
/**************单链表——元素的删除*****************/
//1、定义两个指针变量P1、P2,P1指向头节点,P2指向头节点的下一个节点
//2、使用循环,使P1、P2同时往后移,当P2指向要删除的这个节点时,结束循环
//3、P1指向的节点里面的指针 保存 P2 下一个节点的地址
//4、释放P2指向的节点
void del(struct node*head,int val)//val表示要被删除的值
{
//P1指向删除节点的前驱节点
//P2指向删除节点
struct node*P1 = head;
struct node*P2 = head->next;
while (P2 != NULL)//P2不为NULL,正在遍历单链表中的数据
{
if (P2->id == val)//当P2指向要被删除的节点时
{
P1->next = P2->next;
free(P2);
P2 = P1->next;
}
else//两个指针变量同时往后移
{
P1 = P1->next;
P2 = P2->next;
}
}
}
六、单链表元素的查找
int find(struct node*head, int val)//val表示要查找的值
{
int flag = 0;//标记是第几个节点
struct node*p = head->next;
while (p != NULL)
{
flag++;
if (p->id == val)//找到要查找的值
{
printf("这个值:%d 在第 %d 个位置\n\n", p->id,flag);
}
p = p->next;
}
return val;
}
七、单链表元素的修改
void change(struct node*head, int val,int data)//val表示要被修改的值 ,data要被修改成的值
{
struct node*p = head->next;
while (p != NULL)
{
if (p->id == val)//找到要查找的值
{
p->id = data;
}
p = p->next;
}
}
八、整个链表节点的释放
//需要改变主函数中head的值吗? 需要
void Allclear(struct node**list)//&head传过来 list=&head
{
struct node*p = (*list)->next;//p指向头节点的下一个节点
while (p != NULL)
{
//1、头节点里面的指针成员 保存 p指向的下一个节点的地址
//2、释放p节点
//3、更新要删除的节点,p指向头节点后的第一个节点
(*list)->next = p->next;
free(p);
p = (*list)->next;
}
free(*list);//释放头节点
*list = NULL;
}
九、主函数
//***********单链表——头节点的初始化
//头指针变量——保存单链表节点的首地址
struct node* head = NULL;
head = init();
//单链表元——元素的增加
//头插法
for (int j = 1; j <= 5; j++)
{
insert(head, j);
}
print(head);
//尾插法
for (int j = 1; j <= 5; j++)
{
insertEnd(head, j);
}
print2(head);
//单链表元——元素的删除
del(head, 3);
print(head);
//单链表元——元素的查找、修改
find(head, 3);
change(head, 3, 66);
print(head);
//单链表元——节点的释放
Allclear(&head);
printf("%p", head);
print(head);
return 0;
}