很少接触函数题,现在才发现,函数题比从零开始敲难多了。它能够把几乎所有的库限制住,还能限制参数,传给你什么参数你就必须用什么参数,诶嘛,我太难了。
所以,本九研究这五道题用了半个晚上加一个上午才搞明白。
第一题 小试牛刀,不成气候
本题要求实现一个函数,找到并返回链式表的第K个元素。
函数接口定义:
ElementType FindKth( List L, int K );
其中List结构定义如下:
typedef struct LNode *PtrToLNode;
struct LNode {
ElementType Data;
PtrToLNode Next;
};
typedef PtrToLNode List;
L是给定单链表,函数FindKth要返回链式表的第K个元素。如果该元素不存在,则返回ERROR。
裁判测试程序样例:
#include <stdio.h>
#include <stdlib.h>
#define ERROR -1
typedef int ElementType;
typedef struct LNode *PtrToLNode;
struct LNode {
ElementType Data;
PtrToLNode Next;
};
typedef PtrToLNode List;
List Read(); /* 细节在此不表 */
ElementType FindKth( List L, int K );
int main()
{
int N, K;
ElementType X;
List L = Read();
scanf("%d", &N);
while ( N-- ) {
scanf("%d", &K);
X = FindKth(L, K);
if ( X!= ERROR )
printf("%d ", X);
else
printf("NA ");
}
return 0;
}
/* 你的代码将被嵌在这里 */
输入样例:
1 3 4 5 2 -1
6
3 6 1 5 4 2
输出样例:
4 NA 1 2 5 3
好久不用c了,现在对于c也只是配合一些cpp的使用,所以乍一读题,挺头疼的。而且我很受不了一下子那么多typedef,有点绕。阿不,太绕了!
这道题除了read()函数没写没办法编译之外,都还好,没啥可说的,直接粘代码吧。
ElementType FindKth( List L, int K )
{
if(K<1)
return ERROR;
for(int i=1;i<K&&L!=NULL;i++)
L = L->Next;
if(L==NULL)
return ERROR;
else
return L->Data;
}
第二题 仍然无话可说
6-2 求单链表结点的阶乘和 (15 分)
本题要求实现一个函数,求单链表L结点的阶乘和。这里默认所有结点的值非负,且题目保证结果在int范围内。
函数接口定义:
int FactorialSum( List L );
其中单链表List的定义如下:
typedef struct Node *PtrToNode;
struct Node {
int Data; /* 存储结点数据 */
PtrToNode Next; /* 指向下一个结点的指针 */
};
typedef PtrToNode List; /* 定义单链表类型 */
裁判测试程序样例:
#include <stdio.h>
#include <stdlib.h>
typedef struct Node *PtrToNode;
struct Node {
int Data; /* 存储结点数据 */
PtrToNode Next; /* 指向下一个结点的指针 */
};
typedef PtrToNode List; /* 定义单链表类型 */
int FactorialSum( List L );
int main()
{
int N, i;
List L, p;
scanf("%d", &N);
L = NULL;
for ( i=0; i<N; i++ ) {
p = (List)malloc(sizeof(struct Node));
scanf("%d", &p->Data);
p->Next = L; L = p;
}
printf("%d\n", FactorialSum(L));
return 0;
}
/* 你的代码将被嵌在这里 */
输入样例:
3
5 3 6
输出样例:
846
对于这道题,需要注意的就是它读入的过程。因为对于本九的第一感觉,因为最后一次读入不涉及到next地址指向NULL操作,所以这道题目需要用N来控制循环。但又发现,函数没有传入N啊!
我靠,特喵的,要是从零编程,用N多特喵简单啊!!!
玄机在这里:
L = NULL;
for ( i=0; i<N; i++ ) {
p = (List)malloc(sizeof(struct Node));
scanf("%d", &p->Data);
p->Next = L; L = p;
}
我们来看第一段循环,L=NULL,,p1被开辟出来,然后被装填数据,再然后,P1的next指向了L,也就是NULL,然后L指向了P1刚开辟的空间。这时候,作为第一个被存入的点P1,它的next是空的。
再来看第二段循环,又开了一个P2,P2被装填,P2的next指向了L,也就是p1,然后L指向了P2。
可知,L一直在指向最后一个,而最后一个的NEXT一直在指向前一个,所以说,p这个链表,是倒着被开辟出来的。头指针是L,然后最后一个节点的next就是NULL,所以不必担心,直接操作。
代码如下
//做一个阶乘的函数配合所编写的函数
int jiecheng(int n){
int sum=1;
if(n==0)return 1;
for(int i=1;i<=n;i++)
sum*=i;
return sum;
}
int FactorialSum( List L ){
int sum=0;
while(L!=NULL){
sum+=jiecheng(L->Data);
L=L->Next;
}
return sum;
}
第三题 后边基础
6-3 建立学生信息链表 (20 分)
本题要求实现一个将输入的学生成绩组织成单向链表的简单函数。
函数接口定义:
void input();
该函数利用scanf从输入中获取学生的信息,并将其组织成单向链表。链表节点结构定义如下:
struct stud_node {
int num; /*学号*/
char name[20]; /*姓名*/
int score; /*成绩*/
struct stud_node *next; /*指向下个结点的指针*/
};
单向链表的头尾指针保存在全局变量head和tail中。
输入为若干个学生的信息(学号、姓名、成绩),当输入学号为0时结束。
裁判测试程序样例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct stud_node {
int num;
char name[20];
int score;
struct stud_node *next;
};
struct stud_node *head, *tail;
void input();
int main()
{
struct stud_node *p;
head = tail = NULL;
input();
for ( p = head; p != NULL; p = p->next )
printf("%d %s %d\n", p->num, p->name, p->score);
return 0;
}
/* 你的代码将被嵌在这里 */
输入样例:
1 zhang 78
2 wang 80
3 li 75
4 zhao 85
0
输出样例:
1 zhang 78
2 wang 80
3 li 75
4 zhao 85
这道题目是后面两道题目的基础,昨天晚上把本九绕的哇,我靠。
一开始想用一个指针newone来做,后来发现,不大可能,因为next和newone总要和其他的节点关联,用一个很难实现。要不然,为啥第二题非得倒着存储呢?我不知道,但我目前没有设计出来一个正着存储而只需要一个指针的算法。
回头瞅了一眼题,哦,还有一个tail没有用,所以用上了这个tail,配合newone开辟空间,问题就迎刃而解啦~
代码如下:
void input()
{
struct stud_node *newone;
newone=(struct stud_node *)malloc(sizeof(struct stud_node));
scanf("%d", &newone->num);
while(newone->num != 0)
{
scanf("%s %d", newone->name, &newone->score);
if(head == NULL)//只在第一个节点的时候更新head
{
head = newone;
head->next = NULL;
}
if(tail != NULL)//只在第一个节点的时候不更新tail
{
tail->next = newone;
}
tail = newone;
tail->next = NULL;
newone=(struct stud_node *)malloc(sizeof(struct stud_node));
scanf("%d", &newone->num);
}}
第四题 你比三题多一题~~~~~~~~~~~
本题要求实现两个函数,一个将输入的学生成绩组织成单向链表;另一个将成绩低于某分数线的学生结点从链表中删除。
函数接口定义:
struct stud_node *createlist();
struct stud_node *deletelist( struct stud_node *head, int min_score );
函数createlist利用scanf从输入中获取学生的信息,将其组织成单向链表,并返回链表头指针。链表节点结构定义如下:
struct stud_node {
int num; /*学号*/
char name[20]; /*姓名*/
int score; /*成绩*/
struct stud_node *next; /*指向下个结点的指针*/
};
输入为若干个学生的信息(学号、姓名、成绩),当输入学号为0时结束。
函数deletelist从以head为头指针的链表中删除成绩低于min_score的学生,并返回结果链表的头指针。
裁判测试程序样例:
#include <stdio.h>
#include <stdlib.h>
struct stud_node {
int num;
char name[20];
int score;
struct stud_node *next;
};
struct stud_node *createlist();
struct stud_node *deletelist( struct stud_node *head, int min_score );
int main()
{
int min_score;
struct stud_node *p, *head = NULL;
head = createlist();
scanf("%d", &min_score);
head = deletelist(head, min_score);
for ( p = head; p != NULL; p = p->next )
printf("%d %s %d\n", p->num, p->name, p->score);
return 0;
}
/* 你的代码将被嵌在这里 */
输入样例:
1 zhang 78
2 wang 80
3 li 75
4 zhao 85
0
80
输出样例:
2 wang 80
4 zhao 85
这个题就多了一个删除而已。因为第三题的读取和第四题的读取基本没差别,第四题就是比第三题多了重新申明头尾指针和返回一个头指针罢了。
而删除呢?
我是这个思路~
先创建一个p指针用来删除相应的下一个节点。
那么问题来了,如果第一个被删除呢?
所以我在走循环之前,先判断第一个能不能留下。如果能留下,在进入循环删除p的next指向的节点,如果不能留下,就一直找一直找,直到有一个节点留下为止。而如果没有头结点留下,那就是都删完了呗~直接返回NULL。
那么后面的找到不符合条件的,直接改next地址为它的下一个。如果符合条件,就只移动遍历指针p就行。所以需要一个删除没删除的bool变量deletesuccess=false。
但是!!!
c里面不能用bool变量吗?为啥给我报错!!???
fuck that damn it!!!
后来用的int型变量用1和0操纵的……(卑微)。
代码如下:
struct stud_node *createlist(){
struct stud_node *newone,*head=NULL,*tail=NULL;
newone=(struct stud_node *)malloc(sizeof(struct stud_node));
scanf("%d", &newone->num);
while(newone->num != 0)
{
scanf("%s %d", newone->name, &newone->score);
if(head == NULL)
{
head = newone;
head->next = NULL;
}
if(tail != NULL)
{
tail->next = newone;
}
tail = newone;
tail->next = NULL;
newone=(struct stud_node *)malloc(sizeof(struct stud_node));
scanf("%d", &newone->num);
}
return head;
};
struct stud_node *deletelist( struct stud_node *head, int min_score )
{
struct stud_node *p;
int deletesuccess;
p=head;
if(head==NULL)return NULL;
else if(head!=NULL){
while(head->score<min_score){
if(head->next==NULL)return NULL;
else{
head=head->next;
p=head;}
}
}
while(p->next!=NULL)
{
deletesuccess=0;
if(p->next->score<min_score)
{
p->next=p->next->next;
deletesuccess=1;
}
if(deletesuccess==0)
p=p->next;
}
return head;
}
第五题 换汤不换药
6-5 删除单链表偶数节点 (20 分)
本题要求实现两个函数,分别将读入的数据存储为单链表、将链表中偶数值的结点删除。链表结点定义如下:
struct ListNode {
int data;
struct ListNode *next;
};
函数接口定义:
struct ListNode *createlist();
struct ListNode *deleteeven( struct ListNode *head );
函数createlist从标准输入读入一系列正整数,按照读入顺序建立单链表。当读到−1时表示输入结束,函数应返回指向单链表头结点的指针。
函数deleteeven将单链表head中偶数值的结点删除,返回结果链表的头指针。
裁判测试程序样例:
#include <stdio.h>
#include <stdlib.h>
struct ListNode {
int data;
struct ListNode *next;
};
struct ListNode *createlist();
struct ListNode *deleteeven( struct ListNode *head );
void printlist( struct ListNode *head )
{
struct ListNode *p = head;
while (p) {
printf("%d ", p->data);
p = p->next;
}
printf("\n");
}
int main()
{
struct ListNode *head;
head = createlist();
head = deleteeven(head);
printlist(head);
return 0;
}
/* 你的代码将被嵌在这里 */
输入样例:
1 2 2 3 4 5 6 7 -1
输出样例:
1 3 5 7
和第四题的差别就是少了俩数据元素,判断方式不一样了而已,就不多说了,会了第四题不会第五题,只能说明一个问题——
你根本不会第四题。
直接粘代码吧:
struct ListNode *createlist(){
struct ListNode *newone,*head=NULL,*tail=NULL;
newone=(struct ListNode*)malloc(sizeof(struct ListNode*));
scanf("%d",&newone->data);
while(newone->data!=-1){
if(head==NULL){
head=newone;
head->next=NULL;
}
if(tail!=NULL){
tail->next=newone;
}
tail=newone;
tail->next=NULL;
newone=(struct ListNode*)malloc(sizeof(struct ListNode*));
scanf("%d",&newone->data);
}
return head;
};
struct ListNode *deleteeven( struct ListNode *head ){
struct ListNode *p;
int deletesuccess;
p=head;
if(head==NULL)return NULL;
else if(head!=NULL){
while(head->data%2==0){
if(head->next!=NULL){
head=head->next;
p=head;}
else return NULL;
}
}
while(p->next!=NULL){
deletesuccess=0;
if(p->next->data%2==0){
p->next=p->next->next;
deletesuccess=1;
}
if(deletesuccess==0){
p=p->next;
}
}
return head;
};