C语言回顾13-结构体深入
-
结构体嵌套
结构体和数组的组合没有限制。数组可以有结果作为元素,结构体里也可以有数组,下面我们来看一下结构内的成员包含结构的例子:
struct info{
int phone;
char sex;
};
struct person{
int name[20];
char address[20];
struct info info;
}p1,p2;
这种把一个结构嵌套到另一个结构里是非常有意义的,我们上面用一个结构体来包含一个人的手机号和性别,然后把他作为另一个结构体的一部分,比如person,这时候person这个结构体里就含有info的结构,这样的好处之一,就是当我们想修改info里的内容时可以只传递一个参数,而不是两个,但数据越来越大,实用性也更高。只不过我们使用的时候就需要两次点号而已。
-
链表
链表是一个很重要的数据结构,很经常使用。开始的时候比较难理解,理解了就觉得很简单。下面我们开始复习链表。
- 什么是链表
链表是由一连串的结构体组成的,这些结构体很特殊他们的成员里都包含和他们类型相同的结构体指针(指针域)和储存数据的成员(数据域),这代表什么呢?则表示他们可以指向一个和他们类型相同的结构体,那么他们就可以通过这种指针的作用链接起来,就称为链表,每一个结构体就叫做节点,一般来说链表的最后一个的结构体的节点要指向NULL,下面是图示;
首先我们先理解链表的结构,接下来我们编程实现它:
- 创建一个链表的步骤
1.声明结构体
首先我们需要一个结构体,这个结构体的要求我们已经说过了。要具有数据域和指针域,我们暂且把数据域定为一个整型的学号,那么这样的结构体是这样的:
struct stu { int num; struct *next; };
这样子,就是一个简单的节点,num用来存放数据,next用来链接下一个节点。
2.创建节点
那么我们怎么创建下一个节点呢?每次都定义一个节点当然可以,但是太麻烦,这里我们要学会使用malloc函数申请内存空间,malloc里有一个整形参数,他会返回一个void类型的指针指向这个整形大小的内存。那么我们可以编写一个函数,用来初始化一个节点;
void IntList(struct *&p) { p=(struct stu*)malloc(sizeof(struct stu)); p->next=NULL; }
这样我们就用一个指针p指向了一块内存,大小刚好为struct stu大小,这里的&是引用的意思,也就是函数不会再创建内存去储存形参,直接使用改变实参。并且我们给它的next赋值为NULL,这样子每一个节点的末尾开始都是NULL,那么结束时末尾一定是NULL。
3.创建头节点
我们要使用链表,一定给有一个开始的地方,就是第一个节点被称为头节点。我们暂且在全局范围定义一个H来充当头节点。
struct stu *H;
这样就可以了吗,很明显我们在main函数开始的时候也应该初始化它,然后我们把后面的节点链接在它后面就形成了链表。
- ->运算符
对于结构体的点号,结构体指针也有相同的运算符->他由一个减号和大于号组成,效果和结构体类似,一些编译器在对指针使用点号的时候也会识别,会自动把点号替换为->,但是我们也要学习使用->
- 在链表中插入节点
插入节点是很重要的操作,我们先来看一下理论:
第一个步骤我们在初始化的时候已经完成了,所以我们的插入函数只需要两步就可以:
void AddList(struct *p) { p->next=H->next; H->next=p; }
这两句代码也很简单,我们把要插入的指针p当成参数传进去,然后插入到H后面就行。
- 搜索链表
这个也很简单,无非就是从头到尾走一遍链表,那么我们让一个指针指向头指针,然后一直让它指向下一个就可以实现,但是该到哪里结束呢?这位就要用到最开始的一个条件,指针一定结束与NULL,那么我们可以设置条件,如果这个指针不等于NULL,就一直往下指,就可以实现遍历链表。
void show() { struct stu *p=H; while(p!=NULL) { p=p->next; } }
这样就可以实现对列表的循环。
- 在链表中删除节点
那么当我们想要删除一个节点的时候应该怎么办呢,可以先看下面的图示理解一下理论;
这里我们先了解具体流程,因为一般删除节点需要结合到遍历链表的方法,因为我们需要找到这个节点,所以在介绍完遍历链表后一起编程实现。
#include <stdlib.h>
#include <stdio.h>
typedef struct info {
int n;
struct info*next;
}Linklist;
Linklist*L;
void intlist(Linklist*&p)
{
p = (Linklist*)malloc(sizeof(Linklist));
p->next = NULL;
}
void addlist(Linklist*p)
{
if (L->n == 0)
{
L->n = p->n;
}
else {
p->next = L;
L = p;
}
}
void Z();
void J();
void G();
void C();
void welcome();
void Z()
{
int i, j = 0;
printf("请输入要增加的数字:\n");
scanf("%d", &i);
Linklist*l, *p = L;
intlist(l);
l->n = i;
printf("请输入要插入第几个空间:\n");
scanf("%d", &j);
while (j-1&&p->n != NULL)
{
p = p->next;
j--;
}
l->n = i; l->next = p->next; p->next = l;
system("cls");
welcome();
}
void S()
{
int n; Linklist*p = L,*l;
intlist(l);
printf("请输入你要删除的数字\n ");
scanf("%d", &n);
while (p != NULL)
{
if (p->next->n == n) {
l = p->next;
p->next = p->next->next;
free(l);
break;
}
p = p->next;
}
system("cls");
welcome();
}
void G()
{
int i;
Linklist*p=L;
printf("请输入你要修改的数字:\n");
scanf("%d", &i);
while (p!= NULL)
{
if (p->n == i) {
printf("修改为:\n");
scanf("%d", &i);
p->n = i;
break;
}
p = p->next;
}
system("cls");
welcome();
}
void C()
{
system("cls");
welcome();
}
void welcome()
{
int n;
Linklist*l=L;
while (l != NULL)
{
printf("%d\t", l->n);
l = l->next;
}
printf("\n请选择:\n1.增\t2.删\t3.查\t4.改\n");
scanf("%d", &n);
switch (n)
{
case 1:Z();
case 2:S();
case 3:C();
case 4:G();
}
}
int main()
{
intlist(L); L->n = 0;
int i;
Linklist*l;
for (i = 1; i < 10; i++)
{
intlist(l);
l->n = i;
addlist(l);
}
welcome();
return 0;
}
这个程序实现了对一套数据的增删改查,就是基于链表实现的,可以多看看,自己试着打一下,加深理解。这部分内容比较难,多多复习吧。
22 : 43