本题要求实现两个函数,分别将读入的数据存储为单链表、将链表中奇数值的结点重新组成一个新的链表。链表结点定义如下:
struct ListNode {
int data;
ListNode *next;
};
函数接口定义:
struct ListNode *readlist();
struct ListNode *getodd( struct ListNode **L );
函数readlist
从标准输入读入一系列正整数,按照读入顺序建立单链表。当读到−1时表示输入结束,函数应返回指向单链表头结点的指针。
函数getodd
将单链表L
中奇数值的结点分离出来,重新组成一个新的链表。返回指向新链表头结点的指针,同时将L
中存储的地址改为删除了奇数值结点后的链表的头结点地址(所以要传入L
的指针)。
裁判测试程序样例:
#include <stdio.h>
#include <stdlib.h>
struct ListNode {
int data;
struct ListNode *next;
};
struct ListNode *readlist();
struct ListNode *getodd( struct ListNode **L );
void printlist( struct ListNode *L )
{
struct ListNode *p = L;
while (p) {
printf("%d ", p->data);
p = p->next;
}
printf("\n");
}
int main()
{
struct ListNode *L, *Odd;
L = readlist();
Odd = getodd(&L);
printlist(Odd);
printlist(L);
return 0;
}
/* 你的代码将被嵌在这里 */
输入样例:
1 2 2 3 4 5 6 7 -1
输出样例:
1 3 5 7
2 2 4 6
答案代码:
//创建单链表
struct ListNode* readlist()
{
struct ListNode*head =(struct ListNode*)malloc(sizeof (struct ListNode));
struct ListNode*tail=head; //定义头指针head便于链表完成后返回
head->next=NULL; //定义tail尾指针便于连接
while (1)
{
struct ListNode*p=(struct ListNode*)malloc(sizeof (struct ListNode));
p->next=NULL;
scanf("%d",&p->data);//创建节点并输入数据
if (p->data==-1) break;//输入-1时停止输入
tail->next=p; //把带有数据的节点连接到链表尾部
tail=tail->next; //将尾指针移动到最新的尾节点上
}
return head;
}
//这里的思路是:遍历主链表,检测到奇数值节点,就把这个节点复制到一个新的链表,从而获得奇数值链表
//在把原有的奇数值节点删除,这样主链表就成了偶数值链表
struct ListNode* getodd(struct ListNode** L)
{
struct ListNode* head = *L; //用来遍历的工具人
struct ListNode* oddhead = (struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode* oddtail = oddhead;
oddhead->next = NULL; //这三行是定义了用来创建奇数链表的三个变量
//head用来创建完后返回头指针,tail用来来连接尾部节点
//还有一个变量在循环中创建,用来新建节点存储数据
while (head->next != NULL)
{
if (head->next->data % 2 != 0) //当下个节点数据为奇数时
{
struct ListNode* oddtemp = (struct ListNode*)malloc(sizeof(struct ListNode));
oddtemp->next = NULL; //创建用于储存奇数的节点
oddtemp->data = head->next->data;//把检测到的奇数复制一份进去
oddtail->next = oddtemp; //ok,直接连上尾部
oddtail = oddtail->next; //把尾部连接器移动到最新的尾部
//先在要把原先的奇数节点删了,并让*L链表不因为它的删除而断裂
struct ListNode* temp = head->next;//定义一个新的工具人用来处理这些事
//先让它指向原来的奇数值节点
head->next = temp->next;//把奇数值节点的下一个节点和head->next连接起来
//这样head->next将不指向这个即将被删除的奇数值节点
//现在可以删除该奇数值节点了
free(temp);//删除后应把temp赋为NULL以防野指针
temp = NULL;
}
else//没有检测到奇数时,就正常遍历即可
{
head = head->next;//移动用来遍历的工具人
}
}
*L = (*L)->next;//头指针没有数据,若直接打印会出乱码,所以把它移到下一个节点
oddhead = oddhead->next;//奇数链表的头指针也是
return oddhead; //把奇数链表返回即可,偶数链表是在原先的主链表的地址上进行的修改,不必返回也有效
//而奇数链表头指针是函数里的局部变量,不返回就被回收了
}