链表笔记(2)
继上一章继续讲解,这一随笔主要记录的链表的删除与链表的插入。
- 链表的删除 :删除链表中指定的数据,一般需要经过三个步骤
- 定位:采用遍历思想,在链表中查找待删除数据所在的结点位置,并用一个指针保存该位置
- 脱链:“脱离”,且剩下结点仍要维持链表关系
- 释放:释放待删除结点的内存空间
- 注释:
例题:在上一例题的基础上增加删除函数Delete
#include<stdio.h> #include<stdlib.h> struct Node { int data; struct Node *next; }; typedef struct Node Node; Node * Create(); void Print(Node *head); void Release(Node *head); Node * Delete(Node *head,int num);//待删除数据值,函数返回值为删除后的头指针
int main() { int num; Node *head; //定义一个头指针 head=Create(); //创建新链表,返回的头指针赋值给head Print(head); //遍历,输出每个元素的值 printf("请输入要删除的数据:\n") ; scanf("%d",&num); head=Delete(head,num); Print(head); Release(head); return 0; }
//函数定义
Node * Create() { Node *head,*tail,*p; //head,tail分别指向头结点和尾结点 int num; head=tail=NULL; //链表初始化:空链表 printf("请输入一批数据,以-999结尾:\n"); scanf("%d",&num); while(num!=-999) //用户输入未结束 { p=(Node *)malloc(sizeof(Node)); //申请一块结点的内存用于存放数据 p->data=num; //将数据存于新结点的data成员中 p->next=NULL; //将新结点的指针赋为空值 if(head==NULL) //如果原来链表为空值 { head=p; //将P值复制给head,p是刚申请的第一个结点 } else { tail->next=p; //如果原来链表为非空 } tail=p; //更新tail指针,让其指向新的结尾处 scanf("%d",&num); } return head; //返回链表的头指针 } void Print(Node * head) { Node *p; //定义工作指针P p=head; //p从头指针开始 if(NULL==head) //如果链表为空输出提示信息 { printf("链表为空\n"); } else { printf("链表如下:\n"); while(p!=NULL) //p为空指针时则停止 { printf("%d",p->data); p=p->next; } } printf("\n"); } void Release(Node *head) { Node *p1,*p2; //p1控制循环,p2指向当前删除结点处 p1=head; while(p1!=NULL) { p2=p1; //p2指向当前删除结点处 p1=p1->next; //p1指向下一结点 free(p2); } printf("链表释放成功!"); }
//重点:Delete函数定义
Node * Delete(Node *head,int num) { Node *p1,*p2; if(NULL==head) //空链表判断 { printf("链表为空!\n"); return head; } p1=head; //p1用于查找待删除结点,从头指针开始 while(p1->next &&p1->data!=num) { p2=p1; //p2用于记下原来p1的值 p1=p1->next; } if(p1->data==num) //找到该数据 { if(head==p1) //如果删除的是第一个结点 { head=p1->next; } else { p2->next=p1->next; } free(p1); printf("删除成功!\n"); } else printf("链表中无次数据!\n"); return head; }
2、链表的插入:
- 若链表中的数据是从小到大存放的,现要求向链表中插入一个结点,并保存数据是从小到大的次序不变
- 三个步骤:(1)生成结点:与创建链表类似,要添加一个新数据,先要动态分配内存的方法生成一个结点,将新数据复制给该点数据域,而该结点的指针域则设为NULL
(2)确定位置:遍历查找,确定位置
(3)插入结点:将该节点插入链表
例题:在第一个随笔的例题下添加Insert函数
include<stdio.h> #include<stdlib.h> struct Node { int data; struct Node *next; }; typedef struct Node Node; Node * Create(); void Print(Node *head); void Release(Node *head); Node * Insert(Node *head,int num);
int main() { int num; Node *head; //定义一个头指针 head=Create(); //创建新链表,返回的头指针赋值给head Print(head); //遍历,输出每个元素的值 printf("请输入要插入的数据:\n") ; scanf("%d",&num); head=Insert(head,num); Print(head); Release(head); return 0; } Node * Create() { Node *head,*tail,*p; //head,tail分别指向头结点和尾结点 int num; head=tail=NULL; //链表初始化:空链表 printf("请输入一批数据,以-999结尾:\n"); scanf("%d",&num); while(num!=-999) //用户输入未结束 { p=(Node *)malloc(sizeof(Node)); //申请一块结点的内存用于存放数据 p->data=num; //将数据存于新结点的data成员中 p->next=NULL; //将新结点的指针赋为空值 if(head==NULL) //如果原来链表为空值 { head=p; //将P值复制给head,p是刚申请的第一个结点 } else { tail->next=p; //如果原来链表为非空 } tail=p; //更新tail指针,让其指向新的结尾处 scanf("%d",&num); } return head; //返回链表的头指针 } void Print(Node * head) { Node *p; //定义工作指针P p=head; //p从头指针开始 if(NULL==head) //如果链表为空输出提示信息 { printf("链表为空\n"); } else { printf("链表如下:\n"); while(p!=NULL) //p为空指针时则停止 { printf("%d",p->data); p=p->next; } } printf("\n"); } void Release(Node *head) { Node *p1,*p2; //p1控制循环,p2指向当前删除结点处 p1=head; while(p1!=NULL) { p2=p1; //p2指向当前删除结点处 p1=p1->next; //p1指向下一结点 free(p2); } printf("链表释放成功!"); }
//重点:Insert函数定义
Node * Insert(Node *head,int num) { Node *p1,*p2,*p; p=(Node *)malloc(sizeof(Node));//为待插入的数据申请一块内存 p->data=num; p->next=NULL; p1=head; while(p1 &&p->data >p1->data) //确定插入位置 { p2=p1; p1=p1->next; } if(p1==head) { head=p; } else { p2->next=p1; } p->next=p1; printf("插入数据成功!\n"); return head; }