数据结构(超详细讲解!!)第二节 链表

1.链表的表示

(1).链式存储结构特点

其结点在存储器中的位置是随意的,即逻辑上相邻的数据元素在物理上不一定相邻。

通过指针来实现,每个存储结点都包含两部分:数据域和指针域。

数据域:存储元素数值数据。

指针域:存储直接后继或者直接前驱的存储位置。

注:牺牲空间效率换取时间效率

(2).与链式存储有关的术语

结点:数据元素的存储映像。由数据域和指针域两部分组成;

链表:n 个结点由指针链组成一个链表。它是线性表的链式存储映像,称为线性表的链式存储结构。

单链表、双链表、多链表、循环链表:

结点只有一个指针域的链表,称为单链表或线性链表。

有两个指针域的链表,称为双链表(但未必是双向链表)。

有多个指针域的链表,称为多链表。

首尾相接的链表称为循环链表。

数据结构(超详细讲解!!)第二节 链表_第1张图片

(3).头指针、头结点和首元结点的区别

头指针是指向链表中第一个结点(或为头结点、或为首元结点)的指针;一般用头指针唯一标识一个单链表。

头结点是在链表的首元结点之前附设的一个结点;数据域内只放空表标志和表长等信息,它不计入表长度。

首元结点是指链表中存储线性表第一个数据元素a1的结点

数据结构(超详细讲解!!)第二节 链表_第2张图片

设置头节点的好处:可以对空表、非空表的情况以及对首元结点进行统一处理,编程更方便。

表示空表:

无头结点时,当头指针的值为空时表示空表;

有头结点时,当头结点的指针域为空时表示空表。

2.用C语言定义链表

1.存储结构

typedef   struct   Node      / * 结点类型定义 * /
{  elemtype  data; 
  struct  node  *next; 
} *LinkList,Node    /* LinkList为单链表的类型名*/ 

结点的申请       p=(Node *)malloc(sizeof(Node));

结点的释放       free(p);

#include
#include

typedef int elemtype;

//定义链表 
typedef struct Node
{elemtype data;
struct Node *next;
}*LinkList,Node;

3.链表的基本操作

(1).初始化链表

//初始化单链表
LinkList InitList(LinkList L)
{
	L=(LinkList)malloc(sizeof(Node));
	L->next=NULL;
	return L;
 } 

(2).头插法建立单链表(逆序建表法)

步骤:

①建立头结点L,并置其指针域为next为空。

②生成新结点p,如果生成新结点失败,则返回头结点L否则继续③。

③读入数据给新结点p的数据域。

④将新结点p的指针域指向首结点。

⑤修改头结点L的指针域,使它指向新结点p。

⑥重复步骤②~ ⑤,直到输入结束标志为止,返回头结点L。

//头插入链表
LinkList Create_LinkListF()
{elemtype ix;
LinkList L;
Node *p;
L=(LinkList)malloc(sizeof(Node));
L->next=NULL;
printf("\n请输入数据直到输入0结束:\n");
scanf(" %d",&ix);
while(ix!=0)
{p=(Node *)malloc(sizeof(Node));
p->data=ix;
p->next=L->next;
L->next=p;
scanf(" %d",&ix);
}
return (L);
 } 

数据结构(超详细讲解!!)第二节 链表_第3张图片

(3).尾插入建表(顺序建表)

步骤:

①建立头结点L,并置其指针域为next为空,同时尾指针rail也指向头结点。

②生成新结点p,如果生成新结点失败,则返回头结点L否则继续③。

③读入数据给新结点p的数据域,并将其指针域设为空。

④将新结点p连入尾结点的后面。

⑤修改尾指针,使它指向新结点p。

⑥重复步骤②~ ⑤,直到输入结束标志为止,返回头结点L。

//尾插法
LinkList Create_LinkListR()
{elemtype ix;
LinkList L;
Node *p,*tail;
L=(LinkList)malloc(sizeof(Node));
L->next=NULL;
tail=L;
printf("\n请输入数据直到输入0结束:\n");
scanf(" %d",&ix);
while(ix!=0)
{p=(Node *)malloc(sizeof(Node));
p->data=ix;
tail->next=p;
tail=p;
tail->next=NULL;
scanf(" %d",&ix);
}
return (L);
 } 

(4).遍历

//遍历
void Print_LinkList(LinkList L)
{Node *p=L->next;
printf("输出链表:"); 
while(p!=NULL)
{printf("\t%d",p->data);
p=p->next;
}
 } 

(5).表长

//表长
int LinkList_Length(LinkList L)
{Node *p=L;
int j=0;
while(p->next)
{p=p->next;
j++;
}
return j;
 } 

(6).按序号查找

//按序号查找
Node *GetData_LinkList(LinkList L,int i)
{Node *p;
int j=0;
if(i<=0)
return NULL;
p=L;
while(p->next&&jnext;
j++;
}
if(i==j) return p;
else return NULL;
 } 

(7).按内容查找

//按内容查找
Node *Search_LinkList(LinkList L,elemtype key)
{Node *p;
p=L->next;
while(p)
if(p->data!=key)
p=p->next;
else
break;
return p;
 } 

(8).后插运算

//后插运算
void InsertAfter_LinkList(Node *p,elemtype x)
{Node *s;
s=(Node *)malloc(sizeof(Node));
s->data=x;
s->next=p->next;
p->next=s;
 } 

(9).带头结点的后插运算

Node * findnode(LinkList L,elemtype x)
{Node *p=L;
while((p->next)&&(p->next->datanext;
return p;
}


//带头节点的后插运算//插入后链表任然升序 
void data_INSERT(LinkList L,elemtype x)
{Node *s,*p;
s=(Node*)malloc(sizeof(Node));
s->data=x;
p=findnode(L,x);
s->next=p->next;
p->next=s;
}

(10).前插操作

//前插操作
void InserBefore_LinkList(LinkList L,Node *p,elemtype x)
{Node *s ,*q;
s=(Node *)malloc(sizeof(Node));
s->data=x;
q=L;
while(q->next!=p)
q=q->next;
s->next=p;
q->next=s; 
 } 
//优化前插运算
void INSERTBEFORE1(Node *p,elemtype x)
{Node *s;
s=(Node *)malloc(sizeof(Node));
s->data=p->data;
s->next=p->next;
p->data=x;
p->next=s;
 } 

(11).在指定序号前插入

//在指定序号前插入
int InsList(LinkList L,int i,elemtype e)
{Node *pre,*s;
int k;
if(i<=0) return 0;
pre=L;
k=0;
while(pre!=NULL&&knext;
k=k+1; 
}
if(!pre)
{printf("插入位置不合法!");
return 0; 
}
s=(Node *)malloc(sizeof(Node));
s->data=e;
s->next=pre->next;
pre->next=s;
return 1;
}

(12).删除后继节点

//删除后继节点
int DeleteAfter_LinkList(Node *p)
{Node *r;
if(!p){return 0;}
r=p->next;
if(!r)
{return 0;}
p->next=r->next;
free(r);
return (1);
 } 

(13).删除指定位置节点

//删除指定位置节点
int DeleteNo_LinkList(LinkList L,int i,elemtype *e)
{Node *p,*r;
int k;
p=L;
k=0;
while(p->next!=NULL&&knext;
k=k+1;
}
if(k!=i-1)
{printf("删除节点的位置不合理!");
return 0;
}
r=p->next;
p->next=p->next->next;
*e=r->data;
free(r);
return 1;
 } 

(14).删除指定节点本身

//删除指定节点本身
int DeleteNode_LinkList(LinkList L,Node *p)
{Node *r;
if(p->next!=NULL)
{p->data=p->next->data;
return (DeleteAfter_LinkList(p));
}
else
{r=L;
while(r->next!=p)
r=r->next;
return (DeleteAfter_LinkList(r));
}
 } 

(15).置空表

 //置空表
LinkList SetNull_LinkList(LinkList L)
{while(L->next)
DeleteAfter_LinkList(L);
return (L);
 } 

4.例题

编写实现单链表基本操作的以下函数,并在此基础上设计一个主程序完成如下功能:

初始化单链表L;

⑵用头插法建立单链表L;

⑶用尾插法建立单链表L;

⑷输出单链表L的长度;

⑸输出单链表L的第i个元素(按位置查找);

⑹输出给定元素的位置(按内容查找);

⑺在第i个元素前插入给定元素(在第i个位置插入);

删除单链表L的第i个元素;

输出单链表;

⑽清空单链表(只保留头结点);

⑾菜单函数;

⑿单链表逆置;

5.答案解析

(1).函数调用关系

main

void menu()菜单

LinkList InitList(LinkList L)初始化单链表

LinkList Create_LinkListF(LinkList L)头插入链表

LinkList Create_LinkListR(LinkList L)尾插法

void Print_LinkList(LinkList L)遍历

int LinkList_Length(LinkList L)表长

Node *GetData_LinkList(LinkList L)按序号查找

int Search_LinkList(LinkList L)按值查找

int InsList(LinkList L)在指定序号前插入

int DeleteNo_LinkList(LinkList L)删除指定位置节点

int DeleteAfter_LinkList(Node *p)删除后继节点

LinkList SetNull_LinkList(LinkList L)置空表

LinkList ReversePosition(LinkList L) 逆置单链表

(2).操作过程

1.菜单

数据结构(超详细讲解!!)第二节 链表_第4张图片

2.创建链表

3.按头插入录入链表

数据结构(超详细讲解!!)第二节 链表_第5张图片

4.输出链表长度

5.按序号查找

正确输入:

数据结构(超详细讲解!!)第二节 链表_第6张图片

错误输入:

数据结构(超详细讲解!!)第二节 链表_第7张图片

数据结构(超详细讲解!!)第二节 链表_第8张图片

6.按内容查找:

正确输入:

数据结构(超详细讲解!!)第二节 链表_第9张图片

错误输入:

数据结构(超详细讲解!!)第二节 链表_第10张图片

7.在指定序号前插入

正确输入:

数据结构(超详细讲解!!)第二节 链表_第11张图片

错误输入:

数据结构(超详细讲解!!)第二节 链表_第12张图片

8.删除指定位置节点

数据结构(超详细讲解!!)第二节 链表_第13张图片

9.输出链表

数据结构(超详细讲解!!)第二节 链表_第14张图片

10逆置链表

数据结构(超详细讲解!!)第二节 链表_第15张图片

11.清空链表

数据结构(超详细讲解!!)第二节 链表_第16张图片

12.返回菜单

数据结构(超详细讲解!!)第二节 链表_第17张图片

13.结束程序

数据结构(超详细讲解!!)第二节 链表_第18张图片

14.尾插法建表

数据结构(超详细讲解!!)第二节 链表_第19张图片

(3).代码

#include
#include
#include
#include

typedef int elemtype;

//定义链表 
typedef struct Node
{elemtype data;
struct Node *next;
}*LinkList,Node;

//初始化单链表
LinkList InitList(LinkList L)
{
	L=(LinkList)malloc(sizeof(Node));
	L->next=NULL;
	printf("创建成功。\n");
	return L;
 } 
 
//头插入链表
LinkList Create_LinkListF(LinkList L)
{elemtype ix;
Node *p;
printf("请输入数据直到输入0结束:\n");
scanf(" %d",&ix);
while(ix!=0)
{p=(Node *)malloc(sizeof(Node));
p->data=ix;
p->next=L->next;
L->next=p;
scanf(" %d",&ix);
}
printf("初始化成功。\n");
return (L);
 } 
 
//尾插法
LinkList Create_LinkListR(LinkList L)
{elemtype ix;
Node *p,*tail;
tail=L;
printf("请输入数据直到输入0结束:\n");
scanf(" %d",&ix);
while(ix!=0)
{p=(Node *)malloc(sizeof(Node));
p->data=ix;
tail->next=p;
tail=p;
tail->next=NULL;
scanf(" %d",&ix);
}
printf("初始化成功。");
return (L);
 } 
 
//遍历
void Print_LinkList(LinkList L)
{
Node *p=L->next;
printf("\n输出链表:"); 
while(p!=NULL)
{printf("\t%d",p->data);
p=p->next;
}
printf("\n");
 } 
 
 //表长
int LinkList_Length(LinkList L)
{Node *p=L;
int j=0;
while(p->next)
{p=p->next;
j++;
}
printf("链表表长为:%d\n",j);
return j;
 } 

//按序号查找
Node *GetData_LinkList(LinkList L)
{
Node *p;
int j=0,i;
printf("请输入需要查找的序号:");
scanf(" %d",&i) ;
if(i<=0)
{printf("输入不合法!\n");
return NULL;
}
p=L;
while(p->next&&jnext;
j++;
}
if(i==j) {printf("内容为%d\n",p->data);
return p;}
else {printf("输入不合法!\n");
return NULL;
}
 } 
 
//按值查找
int Search_LinkList(LinkList L)
{Node *p;
int i;
elemtype key;
printf("请输入需要查找的内容:");
scanf("%d",&key); 
p=L->next;
while(p)
if(p->data!=key)
{p=p->next;
i++;}
else
{printf("序号为:%d\n",i+1);
break;
}
printf("未找到。\n");
return i;
 } 


 //在指定序号前插入
int InsList(LinkList L)
{Node *pre,*s;
int k,i;
elemtype e;
printf("请输入插入位置和内容:");
scanf("%d %d",&i,&e);
if(i<=0) return 0;
pre=L;
k=0;
while(pre!=NULL&&knext;
k=k+1; 
}
if(!pre)
{printf("\n插入位置不合法!\n");
return 0; 
}
s=(Node *)malloc(sizeof(Node));
s->data=e;
s->next=pre->next;
pre->next=s;
printf("\n插入成功\n");
return 1;
}

 
 //删除指定位置节点
int DeleteNo_LinkList(LinkList L)
{Node *p,*r;
int k,i;
printf("\n请输入删除位置:");
scanf("%d",&i);
p=L;
k=0;
while(p->next!=NULL&&knext;
k=k+1;
}
if(k!=i-1)
{printf("\n删除节点的位置不合理!\n");
return 0;
}
r=p->next;
p->next=p->next->next;
free(r);
printf("\n删除成功\n");
return 1;
 } 
 
 //删除后继节点 
 int DeleteAfter_LinkList(Node *p)
{Node *r;
if(!p){return 0;}
r=p->next;
if(!r)
{return 0;}
p->next=r->next;
free(r);
return (1);
 } 
 
 //置空表
LinkList SetNull_LinkList(LinkList L)
{while(L->next)
DeleteAfter_LinkList(L);
printf("清除成功!\n");
return (L);
 } 
 
 Node *GetData2_LinkList(LinkList L,int i)
{
Node *p;
int j=0;
if(i<=0)
return NULL;
p=L;
while(p->next&&jnext;
j++;
}
if(i==j) return p;
else return NULL;
 } 
 
//逆置单链表
LinkList ReversePosition(LinkList L) 
{LinkList L1;
Node *p,*q;
int i,j;
L1=(LinkList)malloc(sizeof(Node));
L1->next=NULL;
j=LinkList_Length(L);
q=L1;
for(i=1;i<=j;i++)
{
p=GetData2_LinkList(L,i);
q=(Node *)malloc(sizeof(Node));
q->data=p->data;
q->next=L1->next;
L1->next=q;
} 
Print_LinkList(L1);
return (L1);
}
 
 
 //菜单
void menu()
{
printf("--------1.初始化链表-----------------\n"); 
printf("--------2.头插入法建立顺序表---------\n"); 
printf("--------3.尾插入法建立顺序表---------\n"); 
printf("--------4.输出链表的长度-------------\n"); 
printf("--------5.按位置查找链表-------------\n"); 
printf("--------6.按内容查找链表-------------\n"); 
printf("--------7.插入元素-------------------\n"); 
printf("--------8.删除元素-------------------\n"); 
printf("--------9.输出链表-------------------\n");
printf("--------10.清空链表------------------\n");
printf("--------11.返回菜单------------------\n"); 
printf("--------12.逆置单链表----------------\n");
printf("--------13.退出程序------------------\n");
printf("-------------请输入需要执行的内容:\n");  
 } 
 
 //主函数 
int main()
{LinkList L; 
Node *q;
int i,a,quit=0; 
menu();
while(1)
{
scanf("%d",&a);
switch(a)
{
case 1:L=InitList(L);break;
case 2:L=Create_LinkListF(L);break;
case 3:L=Create_LinkListR(L);break;
case 4:i=LinkList_Length(L);break;
case 5:q=GetData_LinkList(L);break;
case 6:i=Search_LinkList(L);break;
case 7:i=InsList(L);break;
case 8:i=DeleteNo_LinkList(L);break;
case 9:Print_LinkList(L);break;
case 10:L=SetNull_LinkList(L);break;
case 11:menu();break;
case 12:L=ReversePosition(L) ;break;
case 13:quit=1;break;
default:printf("输入1~13之间的数字\n");break;
}
if(quit==1)
{break;
}
}
return 0;
}

你可能感兴趣的:(数据结构(超详细讲解!!),数据结构,链表)