本实验取材于浙江大学《数据结构》.
听过姥姥讲的小白专场知道,这道题卡的是多余结点。姥姥讲的非常仔细,但是代码如何去写有是一个问题。拿到题目的时候惊慌了一下,努力坚持要写下去。
一个好的c语言包含了三样东西
- 输入
- 处理
- 输出
很显然这道题的难点在于处理,下面给出
#include<stdio.h>
#include<stdlib.h>
#define MAXLEN 100002
struct node{
int data;
int next;
}workArray[MAXLEN];
int k,head;//k是你需要反转的个数
struct node workArray[MAXLEN];//结构体数组
int Input(struct node array[]){
int i,inputHead,inputLength;
int index,data,next;
scanf("%d %d %d",&inputHead,&inputLength,&k);
for(i=0;i<inputLength;i++){
scanf("%d %d %d",&index,&data,&next);
array[index].data = data;
array[index].next = next;
}
return inputHead;
}
//有什么感想呢?对这道题目的感想就是,你肯要有输入
//首先输入头结点 结点个数 想要逆转节点个数
//然后遍历 将输入第一个值变成数组的索引即index
//第二个值也就是4 3 2 1 那种data域里的值。
//第三个值就是下一个索引也就是你的吓一跳,把这些存入到数组里
//然后开始后续操作。
int count(int head,struct node array[]){
int i,cnt = 1;
i = head;
while(array[i].next!=-1){
cnt++;
i = array[i].next;
}
return cnt;
}
//这个函数的什么作用呢?就是数清楚节点的个数,因为题目很坏
//他会输入一些无用的节点,程序用一次遍历去遍历出到底
//输入者输入了多少个结点。
void PrintList(int head,struct node array[])
{
int idx = head;
while(array[idx].next != -1){
printf("%05d %d %05d\n",idx,array[idx].data,array[idx].next);
idx = array[idx].next;
}
printf("%05d %d %d",idx,array[idx].data,array[idx].next);
}
//这就是根据索引也就是next进行遍历,输出满足格式打印
int ReverseList(struct node array[],int *head,int k){
int cnt;
if(k==1)
return -1;
cnt = count(*head,array);
int i,ptr1,ptr2,ptr3,firstflag=0,nexthead=*head,lastend=-2;
while(cnt>=k){
ptr1 = nexthead;
ptr2 = array[ptr1].next;
for(i=1;i<k;i++)
{
ptr3 = array[ptr2].next;//临时变量粗存老的下一条地址
array[ptr2].next =ptr1;//将1的索引放进2的里面
ptr1= ptr2;//结点转向下一个地址
ptr2 = ptr3;//老结点继续唯一
}
array[nexthead].next=ptr3;
if(firstflag==0){
lastend = nexthead;
*head = ptr1;
}else{
array[lastend].next = ptr1;
lastend = nexthead;
}
firstflag++;
nexthead = ptr2;
cnt-=k;
}
}
int main()
{
head = Input(workArray);
ReverseList(workArray,&head,k);
PrintList(head,workArray);
return 0;
}
拿到程序直接先看主函数,其他先不要看。
它调用的是一个输入,再者是处理,最后是输出。
int Input(struct node array[]){
int i,inputHead,inputLength;
int index,data,next;
scanf("%d %d %d",&inputHead,&inputLength,&k);
for(i=0;i<inputLength;i++){
scanf("%d %d %d",&index,&data,&next);
array[index].data = data;
array[index].next = next;
}
return inputHead;
}
解释:将一个结构体数组作为一个函数参数传进来,那么结构体数组长什么样子呢?
struct node{
int data;
int next;
}workArray[MAXLEN];
int k,head;//k是你需要反转的个数
struct node workArray[MAXLEN];//结构体数组
结构体就存放数据域和下一个索引地址的域,在对格式的输入时,先输入头结点,然后是输入你想要存入的个数,最后输入想要逆转结点个数。
将输入的一个参数作为数组的索引进行存储,这是亮点!
当输入完毕时,会发现进入了,下一个模块,反转链表!
int ReverseList(struct node array[],int *head,int k){
int cnt;
if(k==1)
return -1;
cnt = count(*head,array);
int i,ptr1,ptr2,ptr3,firstflag=0,nexthead=*head,lastend=-2;
while(cnt>=k){
ptr1 = nexthead;
ptr2 = array[ptr1].next;
for(i=1;i<k;i++)
{
ptr3 = array[ptr2].next;//临时变量粗存老的下一条地址
array[ptr2].next =ptr1;//将1的索引放进2的里面
ptr1= ptr2;//结点转向下一个地址
ptr2 = ptr3;//老结点继续唯一
}
array[nexthead].next=ptr3;
if(firstflag==0){
lastend = nexthead;
*head = ptr1;
}else{
array[lastend].next = ptr1;
lastend = nexthead;
}
firstflag++;
nexthead = ptr2;
cnt-=k;
}
}
代码需要一行行来看,当自身能力越来越强时,看的代码速度就会越来越快。因为给出反转链表的个数,却没有确定自身链表有几个,所以先遍历链表。
int count(int head,struct node array[]){
int i,cnt = 1;
i = head;
while(array[i].next!=-1){
cnt++;
i = array[i].next;
}
return cnt;
}
这是用索引遍历,通过-1确定整个流程安排。然后继续阅读代码,会发现申明了一大堆变量,ptr1,ptr2,ptr3都是拿来用反转链表的后两个,是拿来存索引的,索引存进去的,我就可以实现整个链表的存储。根据结点个数和反转的个数进行反转链表,类似于链表的插入,这里看我的代码注释就很清楚了。当就一个元素反转,他需要存储的是自己为最后一个地址。可以参考这张图
当这些都逆转完毕,索引都存储好时,最后来一个遍历就结束战斗
void PrintList(int head,struct node array[])
{
int idx = head;
while(array[idx].next != -1){
printf("%05d %d %05d\n",idx,array[idx].data,array[idx].next);
idx = array[idx].next;
}
printf("%05d %d %d",idx,array[idx].data,array[idx].next);
}