一、链表特点
- 储存多种数据类型类型
- 可根据需要动态分配存储空间
- 数组移动中,要对元素进行大范围的移动,耗时间,效率低
二、链表构成
- 链表由一个头指针和若干个节点组成,最后一个节点指向空
- 实现原理:头指针指向链表的第一个节点,第一个节点的指针指向下一个节点,然后依次指到最后一个节点
- 链表的数据结构
struct list_node{
int data;//用于存储数据
struct list_node *next;//指针,可以用来访问节点数据,也可以遍历,指向下一个节点
};
- 节点的创建
typedef struct list_node{
int data;
struct list_node *next;
}list_single;
list_single *create_list_node(int data){//将节点封装为一个函数
list_single *node = NULL;//定义头指针
node = (list_single *)malloc(sizeof(list_single));//分配内存
if (node = NULL){
printf("malloc fair!\n");
}
memset(node,0, sizeof(list_single));//清内存
node->data = data;
node->next = NULL;
return node;
}
- 单链表的尾插
只需实现header->next = new;即使当前指向新的节点 - 单链表的头插
即把新的节点插在两个节点之间 只需实现
now_up->next = new;
new->next = now_down; - 单链表的遍历
需要注意:
不需要打印头节点
判断节点是否到达了稳健点
流程
(1)获取当前节点位置,访问头节点
struct list *p = header;
(2)使头节点指向下一个节点p = p->next;
(3)判断是否为最后一个节点
如果不是 先打印第一个节点的数据 然后移到下一个节点 重复这两个步骤
如果是 直接打印数据
printf("%d",p->data);
while(p->next != NULL){
p = p->next;
}
- 删除节点流程
(1)先定义两个指针,一个表示当前节点,另一个表示当前节点的上一个节点
struct list *p = header;
struct list *prev = NULL;
(2)遍历整个链表,同时保存当前节点的前一个节点
while(p->next != NULL){
prev = p;//保存当前节点的前一个节点
p = p->next;//保存当前偏移的节点
return 0;
} (3)在遍历的过程中查找要删除的数据
while(p->next != NULL){
prev = p;
p = p->next;
if(p->id == data)//查找数据
{
prev->next = p->next;//使前一个节点的指向取代当前节点的指向
}
free(p);
}
- 实操 (1)不可增加删减
#include <stdio.h>
#include <string.h>
struct student{
char name[10];
struct student *next;
};
struct student *create(){
struct student *head,*current,*next;
char flag;
char str[10];
printf("输入姓名:\n");
scanf("%s",str);
head = malloc((struct student *) sizeof(struct student));
strcpy(head->name,str);
current = head;//将当前指针赋给current
printf("是否继续输入\n");//Y or N
scanf ("%s",&flag);
while (flag != 'N')
{
printf("输入姓名:\n");
scanf("%s",str);
next = malloc((struct student *) sizeof(struct student));
strcpy (next->name,str);
current->next = next;//将next指针赋给当前指针
printf("是否继续输入");//Y or N
scanf ("%s",&flag);
}
return head;//返回结构体指针
}
int main(){
struct student *p;
p = create();
while (1){
printf("%s\n",p->name);
if(p->next != NULL){
p = p->next;//使指针p指向下一个指针
} else
{
break;
}
}
}
//可增加删减
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct slist{
int id;
struct slist *next;
}L;
L *create_node(int data){//创建一个节点
L *p = malloc(sizeof(L));//给每个节点分配结构体一样的空间大小
if(p == NULL){
printf("malloc error\n");
return NULL;
}
memset(p,0, sizeof(L));//清内存
p->id = data;
p->next = NULL;
}
void tail_insert(L *pH,L *new){//链表的尾插
L *p = pH;//获取当前位置
while (p->next != NULL){
p = p->next;//移动到下一个节点
}
p->next = new;
}
void top_insert(L *pH,L *new){//链表的头插
L *p = pH;
new->next = p->next;
p->next = new;
}
void Print_node(L *pH){//遍链表历
L *p = pH;
p = p->next;
while (p->next != NULL){
printf("id = %d\n",p->id);
p = p->next;
}
printf("id = %d\n",p->id);
}
int delete_list_node(L *pH,int data){
L *p = pH;//获取当前头节点的文职
L *prev = NULL;
while (p->next != NULL){
prev = p;//保存当前节点的前一个节点的指针
p = p->next;//让当前的指针继续往后移动
if(p->id == data){
if(p->next !=NULL){//普通节点删除
prev->next = p->next;
free(p);
} else{//尾节点删除
prev->next = NULL;
free(p);
}
return 0;
}
}
printf("没有要删除的节点\n");
return -1;
}
void trave_list(L *pH){
L *p = pH->next;//保存第一个节点的位置
L *pBack;
int i =0;
if(p->next == NULL || p == NULL)
return;
while (p->next != NULL){//遍历链表
pBack = p->next;//保存第一个节点的下一个节点
//找到第一个有效节点,其实就是头指针的下一个节点
if(p == pH->next){
p->next = NULL;//第一个有效节点就是最后一个及诶点,所以要指向NULL;
} else{
p->next = pH->next;//尾部链接
}
pH->next = p;//头部链接
p = pBack;//走下一个节点
}
top_insert(pH,p);//插入最后一个节点
}
int main(){
int i;
L *header = create_node(0);
for (i = 0;i<10;i++){
tail_insert(header,create_node(i));
}
Print_node(header);
delete_list_node(header,5);
putchar('\n');
Print_node(header);
putchar('\n');
trave_list(header);
Print_node(header);
return 0;
}
参考:bilibili
未完待续