链表数据结构定义及初始化链表:完成创建一个带表头的空链表的操作。
链表插入和遍历链表输出链表的操作:1.编写一个能向表尾插入结点的函数; 2.编写一个能在表头插入结点的函数; 3.编写一个能遍历链表并输出链表各结点数据元素的函数;
链表逆置:完成算法,能实现将链表中的数据元素逆置。
查找和交换:查找符合条件的结点,并将该结点的值与前驱结点的值交换。
链表销毁:完成destroyLinklist函数,实现链表结点空间的回收(链表的结点所占空间是动态分配的堆空间,程序员应在退出程序时释放动态分配的空间。)
#include <stdio.h>
#include <stdlib.h>
// 第一关代码
struct node
{
int data; // 存放整型数据的 data 成员
struct node *next; // 指向下一个结点的 next 成员
};
struct node *mycreateList()
{
// 创建一个只有一个头结点的空链表
// 头节点的数据域赋值为 0,并将表头结点的地址返回
struct node *head = (struct node *)malloc(sizeof(struct node));
if (head != NULL)
{
head->data = 0;
head->next = NULL;
}
return head;
}
// 第二关代码
void myinsertHead(struct node *head, int insData)
{
// 在头节点为表头的链表中进行头插数据元素 insData 的操作
struct node *insertHead = (struct node *)malloc(sizeof(struct node));
insertHead->data = insData;
insertHead->next = head->next;
head->next = insertHead;
}
void myinsertTail(struct node *head, int insData)
{
// 在头节点为表头的单链表表尾插入数据元素 insData
struct node *newNode = (struct node *)malloc(sizeof(struct node));
struct node *t = head;
newNode->data = insData;
newNode->next = NULL;
while (t->next != NULL)
{
t = t->next;
}
t->next = newNode;
}
void myprintList(struct node *L)
{
// 输出头节点为表头的链表中的数据,每输出一个数据换一行
struct node *p = L->next;
while (p != NULL)
{
printf("%d\n", p->data);
p = p->next;
}
}
// 第三关代码
void reverseList_link(struct node *L)
{
// 实现链表逆置功能
struct node *p;
struct node *q;
p = L->next;
L->next = NULL;
while (p != NULL)
{
q = p;
p = p->next;
q->next = L->next;
L->next = q;
}
}
// 第四关代码
int locateAndChange(struct node *L, int data)
{
// 在头结点为 L 的链表中查找与 data 值相等的第一个结点,
// 若能找到该结点,则将该结点的值与前驱结点的值交换。
// 若未找到与 data 值相等的结点,则返回值为 -1。
// 若找到的结点无前驱结点,则返回值为 0,否则返回值为前驱结点的值。
struct node *p;
struct node *q;
int t, a, b, flag = 0;
p = L->next;
while (p != NULL)
{
if (p->data == data)
{
a = p->data;
flag = 1; // 记录是否完成查找
break;
}
p = p->next;
}
if (flag == 0)
return -1;
q = L;
while (q != NULL)
{
if (q->next == p)
{
if (q == L)
return 0; // 排除是第一个节点
b = q->data;
t = a;
a = b;
b = t;
return a;
}
q = q->next;
}
}
// 第五关代码
int destroyList(struct node *L)
{
// 将链表 L 的结点空间回收
// 返回值为回收结点的个数,含头结点在内
struct node *p;
int count = 0;
while (L->next)
{
count++;
p = L->next;
L->next = p->next;
free(p);
}
free(L);
return count + 1;
}
step1
int main(void)
{
struct node *L = mycreateList();
int a[]={1,2,3,4,5,6};
for(int i=0;i<6;i++)
if(i%2) myinsertTail(L,a[i]);
else myinsertHead(L,a[i]);
myprintList(L);
}
step2
int main(void)
{
struct node *L = mycreateList();
if(L==NULL)
printf("fail to create");
else
{ printf("success to create");
printf(" %d ",L->data);
}
return 1;
}
step3
int main(void)
{
struct node *pllist = mycreateList() ;
int num ;
int data;
scanf("%d",&num);
for(int i = 0;i < num; i++)
{
scanf("%d",&data);
myinsertTail(pllist, data);
}
reverseList_link(pllist) ;
myprintList(pllist);
}
step4
int main(void)
{
struct node *pllist = mycreateList() ;
int num ;
int data;
int pos ;
scanf("%d",&num);
for(int i = 0;i < num; i++)
{
scanf("%d",&data);
myinsertTail(pllist, data);
}
scanf("%d",&data);
printf("%d",locateAndChange(pllist,data));
}
step5
int main(void)
{
struct node *pllist = mycreateList() ;
int num ;
int data;
int pos ;
scanf("%d",&num);
for(int i = 0;i < num; i++)
{
scanf("%d",&data);
myinsertHead(pllist, data);
}
printf("%d",destroyList(pllist));
}
这段代码实现了对链表的操作,包括创建链表、插入元素、输出链表数据、链表逆置、查找并交换结点值以及销毁链表等功能。
下面是每个函数的详细说明:
-
mycreateList
:创建一个只有一个头结点的空链表。头节点的数据域赋值为0,并将表头结点的地址返回。 -
myinsertHead
:在以头节点为表头的链表中进行头插数据元素的操作。创建一个新的结点,将要插入的数据赋值给新结点的数据域,然后将新结点插入到头结点之后。 -
myinsertTail
:在以头节点为表头的单链表表尾插入数据元素。创建一个新的结点,将要插入的数据赋值给新结点的数据域,然后将新结点插入到链表的尾部。 -
myprintList
:输出以头节点为表头的链表中的数据,每输出一个数据换一行。遍历链表,依次访问每个结点的数据域并打印。 -
reverseList_link
:实现链表逆置功能,将以头节点为表头的链表逆序排列。使用两个指针p
和q
,分别指向当前遍历到的结点和它的前一个结点,逐个修改结点的指针方向实现逆置。 -
locateAndChange
:在以头结点为表头的链表中查找与给定值相等的第一个结点。若找到该结点,则将该结点的值与前驱结点的值交换。若未找到相等的结点,则返回值为-1。若找到的结点无前驱结点(即为头结点),则返回值为0;否则返回值为前驱结点的值。 -
destroyList
:将链表的结点空间回收,销毁链表。遍历链表,依次释放每个结点的空间,并统计回收的结点个数。最后释放头结点的空间,返回回收的结点个数(包括头结点在内)。