您的位置:首页 > 理论基础 > 数据结构算法

数据结构(C语言版)全程更新第二篇震撼来袭

2015-12-17 10:27 447 查看

单链表的使用

在数据结构中,根据元素之间的不同特性,通常有下列4类基本结构:集合、线性结构、树形结构、图状结构或网状结构。本次,笔者将会奉上豪华的链表套餐,希望新学者可以更快的掌握单链表的插入、删除操作。
线性结构中有两种存储结构,一种是顺序存储结构,一种是链式存储结构,本次,只会接受链式存储结构,之后会补更顺序存储结构。
顺序存储结构查找比较方便,但是插入和删除操作需要移动大量元素,因此插入和删除较为麻烦,而单链表却刚好与之相反,它插入和删除比较方便,但查找却麻烦。因此何时使用链式和顺序,需要根据自己的需求合理使用,从而达到效率最大化。
对于链表,之前我们介绍过了,它的插入和删除比较方便,因此在实际应用中,我们常常会使用到这两个操作,因为笔者不怎么会使用编辑器,不会画动态图,所以可能很难把这个问题给大家演示清楚,但是笔者还是会尽力在代码中多加注释,方便大家的理解。如果大家有课本的话,对照课本中的动态图,再结合笔者的注释和通俗易懂的代码,相信大家都能很快的掌握对于单链表的使用。加油


/*
1、程序设计规划(实现的功能、分几个模块、子函数)
2、 编写单链表创建子函数
3、 编写单链表插入某个结点的子函数                提示:在插入到第i个位置时,要先找到第i-1的结点,然后操作
4、 编写单链表删除某个结点的子函数                提示:在删除到第i个位置时,也要先找到第i-1的结点,然后操作
5、 编写单链表查询某个结点的子函数
6、 编写单链表显示子函数
7、 编写主函数Main(),通过功能菜单调用子函数
8、 编译调试程序
*/
//本程序中函数名的定义规则:多单次组合时第一个单次首字母小写,第二个单词开始每个单次首字母大写(采用了java中的方法的命名规则)
#include<stdio.h>
#include<stdlib.h>

typedef int Status;			//在这里给int起别名Status
typedef int ElemType;		//在这里给int起别名ElemType

//建立结构体,通过结构体建立链表指针、next域、data域
typedef struct LNode{
ElemType data;             //data域,用来存放结点中的值
struct LNode *next;		   //用来指向下一个结点
}LNode,*LinkList;
//打印链表
void printList(LinkList &L)
{
LinkList p;	//定义变量p
p=L->next;		//将p变为第一个结点(头结点的下一个)
while(p!=NULL){  //当p不空时候循环
printf("%d\t",p->data);	//输出结点p对应的值;
p=p->next;				//令p指向p的下一个结点
}
printf("\n");
}
//建立一个创造链表并初始化的函数
void creatList(LinkList &L,Status number)	//number为链表中结点的个数
{
L=(LinkList)malloc(sizeof(LNode));	   //为L动态分配内存空间
if(L==NULL){						   //增强代码的健壮性
printf("动态内存分配失败\n");
exit(0);                           //退出程序
}
L->next=NULL;    //将表置空
LinkList p=L;	  //创建将结点p并指向L
LinkList q;      //创建结点q
//初始化链表
for(int i=1;i<=number;i++){        //循环语句
q=(LinkList)malloc(sizeof(LNode));      //给结点q动态开辟空间
if(q==NULL){                    		//同理在增强代码健壮性
printf("为结点动态分配空间失败:");
exit(0);
}
p->next=q;              // 将结点p的下一个结点指向q
p=q;					// 将结点p移动到q的位置
printf("data:");
scanf("%d",&(q->data)); // 给q的data域赋值
q->next=NULL;			// 将q的下一个置空
}
}
//该函数的功能为给第location个位置插入元素data
void insertList(LinkList &L,int location,int data)//location表示链表的第location个结点 , data表示为插入的数为data
{
LinkList p=L;					//创建将结点p并指向L
LinkList q;						//创建结点q
q=(LinkList)malloc(sizeof(LNode));     //为q动态分配内存空间
if(q==NULL){                    		//同理在增强代码健壮性
printf("为结点动态分配空间失败:");
exit(0);
}
//思考为什么是要找到location-1的位置,将p放到location-1这个位置 可以画图方便理解
for(int i=1;i<=location-1;i++){
p=p->next;
}
q->next=p->next;		//将q的指向的下一个结点指向p目前的下一个结点,这样就断开了p和p的下一个结点直接的线
p->next=q;				//接着将p的下一个结点指向q这样q就插入进来了
q->data=data;              //这里的=后边的data是函数传来的data,别混淆了
printList(L);      //打印新的链表
}
//删除链表中的某个值的函数
void deleteList(LinkList &L,int location) //location表示要删除的第某个结点
{
LinkList p=L;	     //创建将结点p并指向L
LinkList q;			 //创建结点q
//为什么在q没有分配内存空间时候一样可以使用?
q=(LinkList)malloc(sizeof(LNode));
if(q==NULL){                    		//同理在增强代码健壮性
printf("为结点动态分配空间失败:");
exit(0);
}
Status data;		 //用于存储被删除的结点所对应的值,并输出
for(int i=1;i<=location-1;i++){        //还是找位置location-1
p=p->next;
}
q=p->next;                   //将q放在p的下一个结点
p->next=q->next;			//断开p指向q的线,使线指到q的next的位置。相当于把q架空了
q->next=NULL;				//使结点q的下一个指向置空
data=q->data;				//用data存储将要被删除的结点q中的值
free(q);					//释放q
printf("删除的结点的数值为:%d",data);
printf("\n");
printf("删除后的链表为:");   //打印新的链表
printList(L);
}
//查找链表中某个位置结点的值,因为之前的插入和删除操作的使用,链表的值已经变化了,不再是第一你输入的时候的链表值了。所以别混淆了
void seekList(LinkList L,int location)           //location表示的是查找的那个元素的位置
{
LinkList p=L;								 //创建将结点p并指向L
for(int i=1;i<=location;i++){                //遍历链表找到你想操作的那个结点
p=p->next;
}
printf("你所查找的位置的结点的值为:");
printf("%d",p->data);                       //输出该结点data域中的值
printf("\n");
}
//销毁链表
void destoryList(LinkList &L)
{
LinkList p=L;             //到了这里相信大家都发现了这个。每个函数都出来一次,为什么?自己思考下
while(L){	 //销毁链表时候要一个结点一个结点的删除,所以这里采用了循环语句
p=L->next;			 //一个结点一个结点的删除
free(L);
L=p;
}
printf("线性表已被成功销毁\n");
}
//菜单函数,实现各项功能
void Menu(void)
{
LinkList L;
Status a;				//用于控制开关
Status number;				//用于指示链表中结点的个数
Status location,data;			//用于函数传参时候数据的操作

while(1){
printf("\t\t---------实现单链表的创建请按1:---------\n");
printf("\t\t---------插入单链表的结点请按2:---------\n");
printf("\t\t-------删除单链表的某个结点请按3:-------\n");
printf("\t\t---------实现单链表的查找请按4:---------\n");
printf("\t\t---------实现单链表的销毁请按5:---------\n");
printf("\t\t---------------退出请按6:---------------\n");
scanf("%d",&a);
switch(a){
case 1:
printf("请输入链表的结点个数:");
scanf("%d",&number);
creatList(L,number);					//创建链表      //在调用函数时参数切不可写成这样creatList(&L,number);注意下初学者比较容易犯错
printf("是否需要打印出链表中的值:(是请按T,否请按N)\n");
char flag;                //在判断时候用的变量
scanf("%s",&flag);		//scanf("%c",&flag) 会被跳过scanf不信你试试 (*^__^*) ……
if(flag=='T'){
printList(L);
}
else{       //这里的代码是为了增强健壮性,觉得太冗长的人可以注释掉
if(flag=='N'){
break;
}
else{
printf("输入有误请按要求输入\n");
break;
}
}
break;
case 2:
printf("请输入你想在第几个位置插入元素:");
scanf("%d",&location);
printf("\n");
printf("请输入你要插入的元素:");
scanf("%d",&data);
insertList(L,location,data);                    //插入链表,在第location个位置插入元素data
break;
case 3:
printf("请输入你想删除第几个位置的元素:");
scanf("%d",&location);
deleteList(L,location);						//删除链表中的某个位置的元素
break;
case 4:
printf("输入你想查看的第几个结点的值:");
scanf("%d",&location); 						//查找第location个结点
seekList(L,location);					   //寻找链表中的某个结点
break;
case 5:
destoryList(L); 					   //使用完了销毁链表
break;
case 6:
exit(0);
break;
}
}
}
//主函数 用来调用子函数
Status main(void)
{
Menu();
system("pause");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: