1、中级阶段-day1作业
使用的代码
#include<stdio.h>
typedef struct Student
{
int num;
char name[20];
char sex;
}Stu;
int main()
{
Stu s;
scanf("%d%s %c", &s.num, s.name, &s.sex);//读取字符串时,scanf()的占位符用%s即可,用字符数组存放读取的字符串
printf("%d %s %c\n", s.num, s.name, s.sex);
return 0;
}
说明:
scanf()用%s作为占位符读取字符串存放到字符数组时,在字符数组空间足够的情况下,会在最后一个字符后面补上一个\0作为结束符,但是没有换行符。
2、中级阶段-day2作业
使用的代码
#include<stdio.h>
#include<stdlib.h>//malloc的头文件可以是<stdlib.h>也可是<malloc.h>。通常用<stdlib.h>
void modify_point(char*& p)
{
p = (char*)malloc(100);//使用引用,在子函数内申请的空间在主函数可以继续使用该指针访问申请的空间
fgets(p, 100, stdin);//
}
int main()
{
char* p=NULL;//定义指针时,给指针初始化为NULL
modify_point(p);
puts(p);
return 0;
}
3、中级阶段-day3作业
#include<stdio.h>
#include<stdlib.h>
#define MaxSize 50
typedef int ElemType;//顺序表中的元素类型
typedef struct
{
ElemType data[MaxSize];//创建数组
int length;//记录当前数组中有效数据的个数
}SqList;//给结构体重命名为SqList
//插入函数
bool ListInsert(SqList& L, int i, ElemType e)//使用引用,在子函数内对顺序表进行插入操作才能影响外面的顺序表.这里的i表示位置
{
if (i<1 || i>L.length + 1)//判断插入的位置是否合法
{
return false;
}
if (L.length >= MaxSize)//判断是否有空间可以插入
{
return false;
}
for (int j = L.length; j >= i; j--)//length是最后一个元素的位置,是最后一个元素后面一个空间的下标,length-1是最后一个元素的下标
{
L.data[j] = L.data[j - 1];//将后面的元素向后移动一位
}
L.data[i - 1] = e;
L.length++;
return true;//走到此处,表示插入成功
}
//删除使用元素e的引用的目的是拿出对应的值
bool ListDelete(SqList& L, int i, ElemType& e)//因为要将删除的元素传回到主函数中,所以存放删除的元素的变量需要借助引用,即可影响主函数中的变量
{
if (i<1 || i>L.length)//删除的位置必须有元素,相对与插入,插入可以访问到最后元素+1的空间即length+1,但是删除只能访问到最后一个元素的空间也就是length
{
return false;
}
if (L.length == 0)
{
return false;
}
e = L.data[i - 1];//获取删除位置处对应的元素
for (int j = i; j < L.length; j++)
{
L.data[j - 1] = L.data[j];
}
L.length--;
return true;
}
//打印函数
void PrintList(SqList L)//打印顺序表中的数据
{
for (int i = 0; i < L.length; i++)
{
printf("%3d", L.data[i]);//将所有元素打印到同一行
}
printf("\n");
}
int main()
{
SqList L;//创建循序表,命名为L:顺序表是一个结构体,内部有一个存放元素的数组,还有一个记录数组元素个数的整型变量
bool ret_1;
bool ret_2;
ElemType del;
int add_p;
int del_p;
scanf("%d", &add_p);
L.data[0] = 1;
L.data[1] = 2;
L.data[2] = 3;
L.length = 3;//顺序表中的数组每增加一个元素,记录元素个数的整型变量就要加一
ret_1 = ListInsert(L, add_p, 60);//向顺序表L的第二个位置插入60这个元素
if (ret_1)
{
PrintList(L);//打印插入成功后的顺序表
}
else {
printf("false\n");
}
scanf("%d", &del_p);
ret_2 = ListDelete(L, del_p, del);//将顺序表L的第一个位置的元素删除,并将删除的元素传回到主函数中
if (ret_2)
{
printf("删除成功\n");
printf("删除的元素值为%d\n", del);
PrintList(L);
}
else {
printf("删除失败\n");
}
return 0;
}
4、线性表的链式存储
A.单链表的定义
a.理论说明
头节点:单链表的第一个节点,内部没有数据,只有指向第一个节点的指针。
头指针:指向头节点的指针。
b.代码说明
①链表结构体的定义说明
链表结构体,就是一个节点。内部包含一个类型的变量,和一个指向下一节点的指针。这个指针的类型就是用该结构体定义的。但是不能用结构体的别名定义。
代码如下
typedef struct LNode
{
ElemType data;
struct LNode* next;
}LNode,*LinkList;
②用该结构体定义头指针变量
链表头,也就是头指针,类型是该结构体对应的指针
代码如下:
LinkList L;
③用头插法新建链表
Ⅰ.对头插法的说明
即将新申请的节点,放在已有节点的最前面,即放在第一个节点处,这种插入方法称为头插法。
Ⅱ、子函数的书写说明
插入的子函数可以没有返回值。
但是必须引用该头指针。
代码如下
void CreateList(LinkList& L)
Ⅲ.在子函数内申请节点空间
利用malloc()申请的空间地址放到头指针L中。申请的空间大小用sizeof(节点结构体名)计算即可。
申请的地址还需要强制类型转换为指针类型,即节点指针类型。
此时头指针L就对应一个空间,该空间和结构体定义的空间一样,含有一个类型的变量,一个指向下一个节点的指针。
新申请的空间只有一个,没有下一个,所以申请产生的空间指向下一个空间的指针next,需先赋值为NULL。
此时结构如下:
代码如下
LNode* s; int x;
L = (LinkList)malloc(sizeof(LNode));
L->next = NULL;
Ⅳ.先读取一个数据,放到变量中,在利用while循环将读取的数据不断放到新节点中,循环结束前再次读取
即需要在循环中利用malloc申请一个新的空间,放到一个新的节点指针变量中。(这个指针在子函数中定义,在while循环中不断替换使用)。
再将读取的数据放到这个新的节点指针中的数据变量中。
这个新的节点的指针赋值为前一个节点的next值。
结构如下:
代码如下
scanf("%d", &x);//从标准输入读取数据
// 3 4 5 6 7 9999:此时x内是3
while (x != 9999)
{
s = (LinkList)malloc(sizeof(LNode));//申请一个新的空间,也就是存放第一个数据的空间
s->data = x;
s->next = L->next;//让新节点的next指针指向原有的第一个节点(即指向头节点中的next域对应的空间)
L->next = s;//让指针的next域指向新申请的空间节点地址。
scanf("%d", &x);
}
即:
先执行①:将新申请的节点的next与赋值为头指针对应空间中的next值,
再执行②:将头指针对应空间中的next值赋值为新申请的空间的地址。
对scanf()
的补充说明:scanf()
卡住后,若是只有一个占位符,则只读取一个,但是可以输入多个,对于其他没有读取的数据,则会被下一次的scanf()
进行读取。
Ⅵ.整体代码如下
void CreateList(LinkList& L)
{
LNode* s; int x;
L = (LinkList)malloc(sizeof(LNode));
L->next = NULL;
scanf("%d", &x);//从标准输入读取数据
// 3 4 5 6 7 9999:此时x内是3
while (x != 9999)
{
s = (LinkList)malloc(sizeof(LNode));//申请一个新的空间,也就是存放第一个数据的空间
s->data = x;
s->next = L->next;//让新节点的next指针指向原有的第一个节点(即指向头节点中的next域对应的空间)
L->next = s;//让指针的next域指向新申请的空间节点地址。
scanf("%d", &x);
}
}
④链表打印
Ⅰ.子函数名说明:
直接使用形参即可,不需要借助引用,直接传递头指针即可。所以形参也必须是节点指针结构体类型。
代码如下
void PrintList(LinkList L)
Ⅱ.在子函数中改变头指针的值,使其直接指向第一个节点
L=L->next
L本是头指针,指向头节点,头节点中的next指针指向第一个元素节点,即此时L指向第一个元素节点,可以直接使用->访问对应的data域。
Ⅲ.利用while循环,打印节点的data域
while(L!=NULL)//此时L指向第一个元素节点的地址
{
printf("%3d",L->data);//L->data:此时访问的就是第一个元素节点的data域。
L=L->next;//此时L->next是第二个节点的地址,将其放到L中,此时L就指向第二个元素节点地址。直到当前节点中的next域为空后,将其赋值到L指针中,再来到循环判断处,会发现不可再进入。此时的L指向NULL。
}
⑤尾插法新建链表
Ⅰ.对尾插法的逻辑说明
完成的是①的操作,不断的让原有的最后一个节点的next指向新的节点。
Ⅱ.子函数名说明
需要引用头指针,不需要返回。
代码如下
void CreateList2(LinkList& L)
Ⅲ.新建两个结构体指针
①其中一个指针变量指向表尾节点:
若是链表中只有一个头节点,该头节点就是表尾节点。将该节点的地址放到此变量中即可。
结构如下:
②另一个用于在循环中接收malloc()
新建的节点地址
Ⅳ.利用malloc()
新建一个头节点,并赋值给头指针L
malloc()
新建的空间需要强制类型转换为结构体指针类型。
申请的空间大小,使用sizeof()
计算一个结构体的大小即可。
代码如下
L = (LinkList)malloc(sizeof(LNode));
Ⅴ.利用while循环,不断增加节点
在循环中,利用malloc()
申请空间。空间大小用sizeof()
计算一个节点结构体即可。最后需要强制类型转换为节点指针类型。
使用新建节点的指针访问对应的data域,将读取的数据放到新建的节点的data域中。
再将表尾节点的next域赋值为刚申请的空间的地址。
最后令表尾指针指向新的节点即可。
结构如下:
即再循环中执行操作为:
α.malloc()新建节点
β.给节点的data域赋值
γ.将尾指针的next值赋值为新节点的地址(即上图中的①)
δ.将尾指针指向新节点的地址(即上图中的②)
代码如下:
while (x != 9999)
{
s = (LNode*)malloc(sizeof(LNode));
s->data = x;
r->next = s;//让尾部节点的next指向新申请的节点空间
r = s;//r指针指向新的表尾节点
scanf("%d", &x);
}
Ⅵ.循环结束后,再将最后一个节点的next赋值为NULL
尾指针指向表尾节点,该指针使用->即可访问对应的next域,即最后一个节点的next,将其赋值为NULL即可。
代码如下
r->next = NULL;
Ⅶ.整体代码如下:
void CreateList2(LinkList& L)
{
int x;//用于接受放入链表data域中的数据
L = (LinkList)malloc(sizeof(LNode));
LNode* s, * r = L;//r中用于存放表尾节点的地址,指向链表尾部
//3 4 5 6 7 9999
scanf("%d", &x);
while (x != 9999)
{
s = (LNode*)malloc(sizeof(LNode));
s->data = x;
r->next = s;//让尾部节点的next指向新申请的节点空间
r = s;//r指针指向新的表尾节点
scanf("%d", &x);
}
r->next = NULL;//尾节点的next指针赋值为NULL
}