线性结构1 两个有序链表序列的合并
题目已给代码:
#include <stdio.h>
#include <stdlib.h>
typedef int ElementType;
typedef struct Node *PtrToNode;
struct Node {
ElementType Data;
PtrToNode Next;
};
typedef PtrToNode List;
List Read(); /* 细节在此不表 */
void Print( List L ); /* 细节在此不表;空链表将输出NULL */
List Merge( List L1, List L2 );
int main()
{
List L1, L2, L;
L1 = Read();
L2 = Read();
L = Merge(L1, L2);
Print(L);
Print(L1);
Print(L2);
return 0;
}
/* 你的代码将被嵌在这里 */
函数代码:
List Merge(List L1,List L2)
{
List P,rear,t1,t2;
P=(List)malloc(sizeof(struct Node));//PTA提交时要加struct,否则无法通过
rear=P;
t1=L1->Next;//L1,L2带头结点
t2=L2->Next;
while(t1&&t2)
{
if(t1->Data<=t2->Data)
{
rear->Next=t1;
rear=t1;
t1=t1->Next;
}
else if(t1->Data>t2->Data)
{
rear->Next=t2;
rear=t2;
t2=t2->Next;
}
}
rear->Next=t1?t1:t2;
L1->Next=NULL;
L2->Next=NULL;
return P;
}
首先要注意L1,L2还有合并后的链表L都是带头结点的单链表,这就意味着t1,t2开始分别要指向L1,L2的下一个结点,因为空结点Data项是空的。同时Merge()函数内新建链表的头结点不需要删除。审题真的很重要!!!
另外,题目中已说明直接使用原序列中的结点,这就意味着除了头结点需要建立外,不需要建立其他结点,直接从头结点开始依次指向符合条件的t1,t2。注意合并为一个非递减的整数序列。
当t1,t2其中一方为空时,直接将rear->Next赋给不为空的一项即可。(如t1已为空,t2还有剩余项时,此时的t2已经移动到了剩余项中的首项,直接rear->Next=t2,即可完成剩余所有项的合并。)
合并完成后,L1,L2中的输出应为NULL,即完成合并后将L1,L2的头结点置空,为L1->Next=NULL;L2->Next=NULL
还有一点P=(List)malloc(sizeof(struct Node))这条语句中的struct在Dev-C++中可以编译通过,而在PTA却不可以,所以…以后还是写全吧。
线性结构2 一元多项式的乘法与加法运算
#include<iostream>
#include<malloc.h>
using namespace std;
typedef struct PolyNode *Polynomial;
struct PolyNode
{
int coef;
int expon;
Polynomial link;
};
void Attach(int c,int e,Polynomial *prear)
{
Polynomial P;
P=(Polynomial)malloc(sizeof(struct PolyNode));
P->coef=c;//对新结点赋值
P->expon=e;
P->link=NULL;
(*prear)->link=P;
*prear=P; //修改prear的值
}
Polynomial ReadPoly()
{
Polynomial P,rear,t;
int n,c,e;
P=(Polynomial)malloc(sizeof(struct PolyNode));//链表头空结点
P->link=NULL;
rear=P;
scanf("%d",&n);
while(n--)
{
scanf("%d%d",&c,&e);
Attach(c,e,&rear);//将当前项插入多项式尾部
}
t=P;
P=P->link;
free(t);//删除临时生成的空结点
return P;
}
Polynomial Add(Polynomial P1,Polynomial P2)
{
Polynomial P,t,rear,t1,t2;
int sum;
P=(Polynomial)malloc(sizeof(struct PolyNode));
P->link=NULL;
rear=P;
t1=P1;
t2=P2;
while(t1&&t2)
{
if(t1->expon>t2->expon)
{
Attach(t1->coef,t1->expon,&rear);
t1=t1->link;
}
else if(t1->expon<t2->expon)
{
Attach(t2->coef,t2->expon,&rear);
t2=t2->link;
}
else
{
int sum=t1->coef+t2->coef;
if(sum)
{
Attach(sum,t1->expon,&rear);
}
t1=t1->link;
t2=t2->link;
}
}
for(;t1;t1=t1->link)Attach(t1->coef,t1->expon,&rear);//while(t1) {Attach(t1->coef,t1->expon,&rear); t1=t1->link; }
for(;t2;t2=t2->link)Attach(t2->coef,t2->expon,&rear);// while(t2) {Attach(t2->coef,t2->expon,&rear); t2=t2->link; }
t=P;
P=P->link;
rear->link=NULL;
free(t);
return P;
}
Polynomial Mult(Polynomial P1,Polynomial P2)
{
Polynomial P,rear,t,t1,t2;
int c,e;
if(!P1||!P2) return NULL;
P=(Polynomial)malloc(sizeof(struct PolyNode));
P->link=NULL;
rear=P;
t1=P1;
t2=P2;
while(t2)//先用P1的第一项乘以P2,得到P
{
Attach(t1->coef*t2->coef,t1->expon+t2->expon,&rear);
t2=t2->link;
}
t1=t1->link;
while(t1)
{
t2=P2;
rear=P;
while(t2)
{
e=t1->expon+t2->expon;
c=t1->coef*t2->coef;
while(rear->link&&rear->link->expon>e)
rear=rear->link;
if(rear->link&&rear->link->expon==e)
{
if(rear->link->coef+c)
{
rear->link->coef+=c;
}
else
{
t=rear->link;
rear->link=t->link;
free(t);
}
}
else
{
t=(Polynomial)malloc(sizeof(struct PolyNode));
t->coef=c;
t->expon=e;
t->link=rear->link;
rear->link=t;
rear=rear->link;
}
t2=t2->link;
}
t1=t1->link;
}
t2=P;
P=P->link;
free(t2);
return P;
}
void PrintPoly(Polynomial P)
{//输出多项式
int flag=0;//辅助调整输出格式用
if(!P)
{
printf("0 0\n");
return ;
}
while(P)
{
if(!flag)
flag=1;
else
printf(" ");
printf("%d %d",P->coef,P->expon);
P=P->link;
}
printf("\n");
}
int main()
{
Polynomial P1,P2,PP,PS;
P1=ReadPoly();
P2=ReadPoly();
PP=Mult(P1,P2);
PrintPoly(PP);
PS=Add(P1,P2);
PrintPoly(PS);
}
算是现阶段写的最长的代码了吧…因为出错运行的时候电脑死机了两次,苦笑…
for(;t1;t1=t1->link)Attach(t1->coef,t1->expon,&rear);
for(;t2;t2=t2->link)Attach(t2->coef,t2->expon,&rear);
Add()函数中的这两条语句就是让我死机的罪魁祸首,因为写的是
for(;t1;t1->link)Attach(t1->coef,t1->expon,&rear);
for(;t2;t2->link)Attach(t2->coef,t2->expon,&rear);
但是我很好奇为什么这种错误的写法当指数不为0时仍能通过,并且在PTA的测试中不完全错误。之后还要仔细分析分析。
乘法部分让我头疼了好一会儿,一开始没有搞清楚t2和rear的用途,结果导致应该为rear的地方全部写成了t2…rear是为了将新链表从头到尾和新产生结果的系数进行比较,完成插入,合并或删除(新结点与刚开始链表对应结点的指数相同,系数相反)操作,t2是与t1完成系数相乘,指数相加操作。
此题中乘法和加法最初都建立了一个空结点便于操作,最后
需释放此空结点。
PrintPoly()函数中flag设置的也很巧妙,可以避开第一个多打的空格。
线性结构3 Reversing Linked List
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXSIZE 100010
struct node
{
int Data;
int Next;
}node[MAXSIZE];
int main()
{
int first,n,k;
scanf("%d%d%d",&first,&n,&k);
for(int i=0;i<n;i++)
{
int Address,Data,Next;
scanf("%d%d%d",&Address,&Data,&Next);
node[Address].Data=Data;
node[Address].Next=Next;
}
int List[MAXSIZE];
int x=first;
int j=0;
while(x!=-1)
{
List[j]=x;
x=node[x].Next;
j++;
}
int i=0;
while(i+k<=j)
{
reverse(&List[i],&List[i+k]);
i=i+k;
}
int m;
for(m=0;m<j-1;m++)
printf("%05d %d %05d\n",List[m],node[List[m]].Data,List[m+1]);
printf("%05d %d -1\n",List[m],node[List[m]].Data);
}
这题参考了Kunaly大佬的代码,不得不说建立结构数组node[MAXSIZE]和数组List[MAXSIZE]并将其联系起来,这个idea真的很妙。
将node[]的数组下标存储为当前元素的地址,Data,Next分别记为数据和下一项的地址。
使用List[]数组记录从1到n对应的地址,然后使用reverse()函数将相应的位置进行逆转,输出时需特别注意输出的最后一个元素要单独列出来,因为它的Next永远都是-1。