单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。链表中的数据是以结点来表示的,每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。
1. 熟练掌握线性表的基本操作在链式存储结构上的实现
2. 掌握单链表的建立、插入、删除等基本操作;
数据域:存放数据本身的信息。
指针域:存放指向下个结点的地址(指向直接后继的指针)。
结点:数据元素的存储映像。由数据域和指针域两部分组成。
这两部分信息(数据域和指针域)组成数据元素的存储结构,称之为“结点”。n个结点通过指针域相互链接,组成一个链表。
①头指针:永远指向链表中第一个结点的位置(如果链表有头结点,头指针指向头结点;否则,头指针指向首元结点)。
②头结点:一个不存任何数据的空结点,通常作为链表的第一个结点,它的数据域一般不存放数据。(头结点不是必须的。)
③首元结点:链表中第一个元素所在的结点,它是头结点后边的第一个结点。
注意头结点和头指针的区别:头指针是一个指针。。。。。头结点是一个实际存在的结点,它包含有数据域和指针域。
①不带头结点的链表
----头指针为空
②带头结点的链表
----头结点指针域为空
#include"stdio.h"
#include"string.h"
#include"stdlib.h"
#include"ctype.h"
typedef struct node //定义结点
{
char data[10]; //结点的数据域为字符串
struct node *next; //结点的指针域
}ListNode;
typedef ListNode* LinkList; // 自定义LinkList单链表类型
LinkList CreatListR1(void);
ListNode *LocateNode(LinkList head, char *key);
void DeleteList(LinkList head,char *key);
void printlist(LinkList head);
void DeleteAll(LinkList head);
//==========主函数==============
main()
{
char ch[10],num[2];
LinkList head;
head=CreatListR1(); //用尾插入法建立单链表,返回头指针
printlist(head); //遍历链表输出其值
printf(" Delete node (y/n):"); //输入"y"或"n"去选择是否删除结点
scanf("%s",num);
if(strcmp(num,"y")==0 || strcmp(num,"Y")==0){
printf("Please input Delete_data:");
scanf("%s",ch); //输入要删除的字符串
DeleteList(head,ch);
printlist(head);
}
DeleteAll(head); //删除所有结点,释放内存
}
-----什么是尾插法(元素插入链表尾部)
尾插法是从一个空表开始,重复读入数据,生成新结点,将读入数据存放在新结点的数据域中,然后将新结点插入到当前链表的表尾上,直到读入结束标志为止。
//==========用尾插入法建立带头结点的单链表===========
LinkList CreatListR1(void)
{
char ch[10];
LinkList head=(LinkList)malloc(sizeof(ListNode)); //生成头结点
ListNode *s,*r,*pp;
r=head;
r->next=NULL;
printf("Input # to end "); //输入"#"代表输入结束
printf("Please input Node_data:");
scanf("%s",ch); //输入各结点的字符串
while(strcmp(ch,"#")!=0) {
pp=LocateNode(head,ch); //按值查找结点,返回结点指针
if(pp==NULL) { //没有重复的字符串,插入到链表中
s=(ListNode *)malloc(sizeof(ListNode));
strcpy(s->data,ch);
r->next=s;
r=s;
r->next=NULL;
}
printf("Input # to end ");
printf("Please input Node_data:");
scanf("%s",ch);
}
return head; //返回头指针
}
//==========按值查找结点,找到则返回该结点的位置,否则返回NULL==========
ListNode *LocateNode(LinkList head, char *key)
{
ListNode * p=head->next; //从开始结点比较
while( p && (strcmp(p->data,key)!=0 ) ) //直到p为NULL或p-> data为key止
p=p->next; //扫描下一个结点
return p; //若p=NULL则查找失败,否则p指向找到的值为key的结点
}
//==========删除带头结点的单链表中的指定结点=======
void DeleteList(LinkList head,char *key)
{
ListNode *p,*r,*q=head;
p=LocateNode(head,key); //按key值查找结点的
********************
if(p==NULL){
printf("error");
}
while(q->next!=p)
q=q->next;
r=q->next;
q->next=r->next;
free(r);
}
效果如下:根据输入(不允许输入重复的)的字符串,找到相应的结点并删除。
//===========打印链表=======
void printlist(LinkList head)
{
ListNode *p=head->next; //从开始结点打印
while(p){
printf("%s, ",p->data);
p=p->next;
}
printf("\n");
}
//==========删除所有结点,释放空间===========
void DeleteAll(LinkList head)
{
ListNode *p=head,*r;
while(p->next){
r=p->next;
free(p);
p=r;
}
free(p);
}
(1)找到要删除的这个节点:通过遍历来查找节点,从头指针+头节点开始,顺着链表依次找到我们要删除的那个节点。
(2)如果不是尾节点:首先把待删除节点的前一个节点的q->next指向待删除节点的后一个节点的首地址r->next,然后再将这个节点free掉。
(3)如果这个节点是尾节点,首先把待删除这个节点的前一个节点的q->next指针指向NULL,然后再将这个节点free掉。
#include"stdio.h"
#include"string.h"
#include"stdlib.h"
#include"ctype.h"
typedef struct node //定义结点
{
char data[10]; //结点的数据域为字符串
struct node *next; //结点的指针域
}ListNode;
typedef ListNode* LinkList; // 自定义LinkList单链表类型
LinkList CreatListR1(void);
ListNode *LocateNode(LinkList head, char *key);
void DeleteList(LinkList head,char *key);
void printlist(LinkList head);
void DeleteAll(LinkList head);
//==========主函数==============
main()
{
char ch[10],num[2];
LinkList head;
head=CreatListR1(); //用尾插入法建立单链表,返回头指针
printlist(head); //遍历链表输出其值
printf(" Delete node (y/n):"); //输入"y"或"n"去选择是否删除结点
scanf("%s",num);
if(strcmp(num,"y")==0 || strcmp(num,"Y")==0){
printf("Please input Delete_data:");
scanf("%s",ch); //输入要删除的字符串
DeleteList(head,ch);
printlist(head);
}
DeleteAll(head); //删除所有结点,释放内存
}
//==========用尾插入法建立带头结点的单链表===========
LinkList CreatListR1(void)
{
char ch[10];
LinkList head=(LinkList)malloc(sizeof(ListNode)); //生成头结点
ListNode *s,*r,*pp;
r=head;
r->next=NULL;
printf("Input # to end "); //输入"#"代表输入结束
printf("Please input Node_data:");
scanf("%s",ch); //输入各结点的字符串
while(strcmp(ch,"#")!=0) {
pp=LocateNode(head,ch); //按值查找结点,返回结点指针
if(pp==NULL) { //没有重复的字符串,插入到链表中
s=(ListNode *)malloc(sizeof(ListNode));
strcpy(s->data,ch);
r->next=s;
r=s;
r->next=NULL;
}
printf("Input # to end ");
printf("Please input Node_data:");
scanf("%s",ch);
}
return head; //返回头指针
}
//==========按值查找结点,找到则返回该结点的位置,否则返回NULL==========
ListNode *LocateNode(LinkList head, char *key)
{
ListNode * p=head->next; //从开始结点比较
while( p && (strcmp(p->data,key)!=0 ) ) //直到p为NULL或p-> data为key止
p=p->next; //扫描下一个结点
return p; //若p=NULL则查找失败,否则p指向找到的值为key的结点
}
//==========删除带头结点的单链表中的指定结点=======
void DeleteList(LinkList head,char *key)
{
ListNode *p,*r,*q=head;
p=LocateNode(head,key); //按key值查找结点的
if(p==NULL){
printf("error");
exit(0);
}
while(q->next!=p)
q=q->next;
r=q->next;
q->next=r->next;
free(r);
}
//===========打印链表=======
void printlist(LinkList head)
{
ListNode *p=head->next; //从开始结点打印
while(p){
printf("%s, ",p->data);
p=p->next;
}
printf("\n");
}
//==========删除所有结点,释放空间===========
void DeleteAll(LinkList head)
{
ListNode *p=head,*r;
while(p->next){
r=p->next;
free(p);
p=r;
}
free(p);
}