链表的引入和简单应用 ##
@超人不是人
首先我们先引入一个问题:如何让一个用户记录自己一年当中所看过的电影(包括电影名字和用户对它的评价)。
我们用一个结构来记录情况
struct film
{
char title[TSIZE];
int rating ;
}
我们下面简单用几种方式来记录信息
- 程序自定义片名的字符个数(TSIZE)和电影的部数(FMAX)。
struct film movies[FMAX];
缺点:程序浪费大量的空间(片名字符个数因不同的电影而不同)和电影的部数会因不同的用户而不同。不能方便修改。
2.用户自个设定(片名的字符长度和电影的部数),分配合适的存储空间
n设为电影的部数
struct film *movies;
movies=(struct film*)malloc(n*sizeof(struct film));
缺点:都是自己规定死了,不能随时随地的修改,否则也会占用大量内存
3.每次写film是,分配一个内存空间(只足够一个film)
缺点:不能保证每次都是连续的存储空间,且每次都要一个变量来存储此单元。
4创建一个大的指针数组并在分配新结构时逐个对这些指针赋值
struct film *movie[FAMX];
缺点:FMAX依然不能灵活变通,虽然同样的个数的数组比指针内存少的多,但依然存在着浪费(本质问题还没有解决)。
5.最后,引用链表的概念:每次使用malloc分配空间时,也为新的指针分配新的内存空间
方法:需要用另外一个指针来跟踪新分配的指针
创建新的结构时,用前一个结构来存储它的地址。
struct film
{
char title[TSIZE];
int rating ;
struct film *next;//定义指向下一个同样结构的指针
}
第五点就是我们链表的结构的基础了。
## 何为链表呢 ##
按我自己来理解,就是一个结构体指向下一个结构体,下一个又指向下一个结构体,直到最后。
相对于数组来说
优点:内存存储空间大大减少,操作(插入,删除等)元素方便
缺点:理解起来相对的吃力,申请管理空间难度大。
我们先来流程图看一下链表
每个结构体的next都指向下一个结构体,current是当前的操作的链表,即可以是head,footer,也可以是其他的结构体。
初始化结构体
先说一下我们要实现的功能:一开始要输入所看的电影名字和标号,然后可以根据提示(1删除,2增加,3退出)新的结构体
struct film
{
char title[SIZE];
int rating;
struct film *next;
};
typedef struct film movies;
movies *setup()
{
int flag=1,a;
char input[SIZE];
movies *head=NULL;
movies *footer,*current;
printf("请输入第一个电影名字\n");
while(flag)
{
scanf("%s",input);
/*每次都分配一个新的空间*/
current=(movies*)malloc(sizeof(movies));
if(head==NULL)
head=current;
else
footer->next=current;
/*输入变量值*/
current->next=NULL;
strcpy(current->title,input);
printf("这是第几部影片\n");
scanf("%d",¤t->rating);
fflush(stdin);//可以让输入增加容错率,具体百度
printf("你要继续(按1)还是退出(按0)");
scanf("%d",&flag);
fflush(stdin);
if(flag!=0)
printf("请输入下一部影片的名字");
/*保存当前的值*/
footer=current;
}
return head;
}
在里面插入新的结构体和删除其中一个结构体
void insert(movies *ptr,int n)//在第n行插入数据
{
movies *p1,*p2,*swap;
int i;//数数
p1=(movies*)malloc(sizeof(movies));
printf("请输入你要插入的电影题目");
scanf("%s",&p1->title);
fflush(stdin);
printf("请输入电影的标号");
scanf("%d",&p1->rating);
fflush(stdin);
p2=ptr;
/*这个for的意思是找到要插入的p2的位置*/
for (i=0;i<n-1;i++)
{
p2=p2->next;
}
swap=p2->next;
p2->next=p1;
p1->next=swap;
/*这三句我曾经用下面几句话替代,发现地址有冲突,要用一个新的movies结构体(swap)来保存交换的值,p1是插入的结构体,需要仔细的琢磨*/
//p2->next=current->next;
//current->next=p2;
}
void cutdown(movies *ptr,int n)//删除其中一个
{
int i;
movies *swap;
for (i=0;i<n-2;i++)
{
ptr=ptr->next;
}
swap=ptr->next->next;
ptr->next=swap;
}
void printfdown(movies *pr) //输出函数
{
movies *p3;
p3=pr;
while(p3!=NULL)
{
printf("The film title:%s,rating:%d\n",p3->title,p3->rating);
p3=p3->next;
//要用一个p3->next连续指向下一个p3,达到连续输出的结果
}
}
main函数
void main (void) //创建n层链表
{
movies *head,*current;
int function=0,a=0;
head=setup();//把头结构地址赋给head
while(function!=3)
{
printf("删除请按1,增加请按2,退出请按3\n");
scanf("%d",&function);
if(function==3) break;
printf("第几行");
scanf("%d",&a);
current=head;//需要用head导航,寻找位置
switch(function)
{
case 1:cutdown(current,a);break;
case 2:insert(current,a);break;
case 3:break;
}
}
current=head;
printfdown(current);
}
最后:我一开始接触时遇到很多的大大小小问题,这里就通过注释写出来,但是又有很多没有特别标注