一、链表
逻辑结构:线性结构 存储结构:链式存储
分类:有头链表:第一个节点不存储数据,作为头节点
无头链表:第一节点就开始存储数据
循环链表:最后一个节点的指针域指向头节点
双向链表
二、链表的操作
(1).链表的插入
头插法步骤:
1.申请新节点
2.新节点的指针域指向第一个数据节点(也就是头指针指针域指向的那个节点)
3.头指针的指针域指向新节点
尾插法步骤:
1.申请新节点
2.遍历链表,找到最后一个节点
3.让最后一个节点的指针域指向新节点
任意位置插入的步骤:
1.遍历链表,找到待插入位置的上一节点 ptemp
2.申请新节点 pnew
3.pnew->next = ptemp->next
4.ptemp->next = pnew
(2)链表的删除
头删法步骤:
1.定义pdel指向待删除的节点
2.让头结点的指针域指向 pdel的next,也就是第二个节点
3.释放pdel
4.pdel = NULL
尾删法步骤:
1.遍历链表,找到倒数第二个数据节点 ptemp
2.free(ptemp->next)
3.ptemp->next = NULL
任意位置删除步骤:
1.找到待删除节点的前一节点 ptemp
2.定义 pdel = ptemp->next, 也就是说 让pdel指向待删除节点
3.释放 pdel
4.pdel = NULL
链表的相关操作基本都是依赖这些基本的步骤来完成的
三、
1.创建一个链表
首先需要定义一个结构体
typedef struct NODE{
int data; //数据域,以一个int为例,按照自己的需求写
struct NODE *next; //定义一个结构体指针,也就是指针域
}node_t;
然后我们需要主函数中创建一个头结点,然后将头结点传入创建节点的函数
node_t *phead;
创建节点的函数
int create_node(node_t **pnew,int data){ //这里使用二级指针的目的是我们需要将该节点指向NULL
*pnew=(node_t *)malloc(sizeof(node_t));对于创建的新节点我们都需要进行分配空间的操作并且在下边判断空间是否分配成功
if(*pnew==NULL ){
printf(“分配失败\n”);
return -1;
}
(*pnew)->data=data;
(*pnew)->next=NULL;
return 0;
}
2.插入节点
可以使用上边的思路编写,注意对于每个传入的头结点,我们都要做非空检查,并且我们切记在函数中对头结点进行操作,。并且插入一定要先让插入节点指向插入位置的下一节点,然后让上一节点指向插入节点,顺序不能变。
头插法:
node_t *pnew = NULL;
create_node(&pnew, data);
pnew->next = phead->next;
phead->next = pnew;
尾插法:
node *pnew=NULL;
create_node(&pnew,data);
node_t ptemp=phead; //对于需要偏移头指针的操作,我们这样可以避免直接对头指针进行操作,以防止找不打头指针
while(ptemp->next!=NULL){
ptemp=ptemp->next;
}//循环结束后ptemp指向的就是最后一个数据节点
ptemp->next=pnew;
任意位置插入就是需要通过循环找到插入位置的上一个节点,然后插入
2.删除节点
思想:找到删除节点的前一节点,让上一节点指向该节点的下一节点,对于删除的操作,如果要找待删除节点的前一节点,要注意,不能让 ptemp 走到最后一个节点,因为ptemp 走到最后一个节点,就表示 要删除的是ptemp指针域指向的节点,但是此时 ptemp的指针域 为NULL 可能会出现断错误
3.链表的翻转
node_t *p = phead->next->next;
phead->next->next = NULL;
node_t *ptemp = NULL;
while(p != NULL){
ptemp = p->next;//先保存p后面的节点 否则就找不到了
//将节点p 头插进原链表
p->next = phead->next;
phead->next = p;
p = ptemp;//p向后走一步
}