代码改变世界

PAT线性结构_一元多项式求导、按给定步长反转链表、出栈序列存在性判断

2015-06-15 16:51  星星之火✨🔥  阅读(585)  评论(0编辑  收藏  举报
02-线性结构1. 一元多项式求导 (25)
设计函数求一元多项式的导数。(注:xn(n为整数)的一阶导数为n*xn-1。)

输入格式:以指数递降方式输入多项式非零项系数和指数(绝对值均为不超过1000的整数)。数字间以空格分隔。

输出格式:以与输入相同的格式输出导数多项式非零项的系数和指数。数字间以空格分隔,但结尾不能有多余空格。注意“零多项式”的指数和系数都是0,但是表示为“0 0”。

输入样例:
3 4 -5 2 6 1 -2 0
输出样例:
12 3 -10 1 6 0

最简单的方式是用数组模拟,但是毕竟处在学习数据结构阶段,所以还是写了个链表的,如下:

#include<stdio.h>
#include<malloc.h>
typedef struct Node
{
    int coef; // 系数
    int exp; // 指数
    struct Node * next;
}NODE, *PNODE;
int main(void)
{
    int coef, exp;
    PNODE pHead, pTail, pTemp;
    
    pHead = (PNODE)malloc(sizeof(NODE)); // 创建头节点
    pTail = pHead;
    
    while(scanf("%d%d", &coef, &exp) != EOF)
    {
        pTemp = (PNODE)malloc(sizeof(NODE));
        pTemp->coef = coef;
        pTemp->exp = exp; // 注: 因为有尾指针,所以省略了next设为NULL这一步
        pTail->next = pTemp; 
        pTail = pTemp;
    }
    pTail->next = NULL; 
    // 扫描、求值并输出
    pTemp = pHead->next; // 定位到首元素
    if(pTemp->exp == 0) // 首元素指数为零,其求导比较特殊因此单独处理
    {
        printf("0 0"); 
    }
    else
    {
        while(pTemp)
        {
            if(pTemp->exp > 0) // 指数为零的项求导直接为零,不进行输出
            {
                if(pTemp != pHead->next) //如果不是第一个元素输出空格
                    putchar(' ');
                printf("%d %d", pTemp->coef * pTemp->exp, pTemp->exp -1);
            
                pTemp = pTemp->next;
            }
            
            else 
                break;
        }
    }    
    // 注:申请内存没有判断是否成功,内存用完了也没释放,懒le:~
    return 0;
}
02-线性结构2. Reversing Linked List (25)
时间限制
Given a constant K and a singly linked list L, you are supposed to reverse the links of every K elements on L. For example, given L being 1→2→3→4→5→6, if K = 3, then you must output 3→2→1→6→5→4; if K = 4, you must output 4→3→2→1→5→6.

Input Specification:

Each input file contains one test case. For each case, the first line contains the address of the first node, a positive N (<= 105) which is the total number of nodes, and a positive K (<=N) which is the length of the sublist to be reversed. The address of a node is a 5-digit nonnegative integer, and NULL is represented by -1.

Then N lines follow, each describes a node in the format:

Address Data Next

where Address is the position of the node, Data is an integer, and Next is the position of the next node.

Output Specification:

For each case, output the resulting ordered linked list. Each node occupies a line, and is printed in the same format as in the input.

Sample Input:
00100 6 4
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 00000
99999 5 68237
12309 2 33218
Sample Output:
00000 4 33218
33218 3 12309
12309 2 00100
00100 1 99999
99999 5 68237
68237 6 -1

我投机取巧,用了数组模拟,当然也可以用三指针法:

#include<stdio.h> // 大数组模拟
#define MAXN 100000
typedef struct Node
{
    int address;
    int data;
    int next;
}NODE, *PNODE;
NODE node[MAXN+10];
void Swap(NODE node[], int, int);
void Swap2(NODE node[], int, int);
void Reverse(NODE node[], int, int);
int main(void)
{
    int firstAddress, n, k; // 首地址、节点个数、反转长度
    int i, j, address;
    
    scanf("%d%d%d", &firstAddress, &n, &k);
    for(i = 1; i <= n; i++)
    {
        scanf("%d%d%d", &node[i].address, &node[i].data, &node[i].next);
        if(node[i].address == firstAddress)
            j = i;
            
    }
    // 交换第一个元素与应当排在首位的元素,如果多次使用的话应该编写一个函数,传递适当的参数给它完成数据的交换
    Swap(node, 1, j);
    // 首先根据节点地址信息进行排序
    for(i = 2; i <= n; i++)
    {
        address = node[i-1].next;
        if(address == -1) 
        {
            n = i - 1; // 修改n的值达到排除输入数据中无效节点的目的
            break;
        }
        
        for(j = i; j <= n; j++)
            if(address == node[j].address)
            {
                Swap(node, i, j);

                break;
            }
    }
    // printf("n: %d\n", n); // test
    Reverse(node, n, k);
    
    for(i = 1; i < n; i++)
        printf("%05d %d %05d\n", node[i].address, node[i].data, node[i].next); // 0n表示宽度至少为n位,不足以左边0填充
    printf("%05d %d %d\n", node[i].address, node[i].data, node[i].next);
    
    return 0;
}

void Swap(NODE node[], int i, int j)
{
    int temp;
    
    temp = node[i].address;
    node[i].address = node[j].address;
    node[j].address = temp;
    
    temp = node[i].data;
    node[i].data = node[j].data;
    node[j].data = temp;
    
    temp = node[i].next;
    node[i].next = node[j].next;
    node[j].next = temp;
}

void Swap2(NODE node[], int i, int j) // 作为反转操作的一个子函数来使用,注意与Swap函数的不同点,即它不关心next变量
{
    int temp;
    
    temp = node[i].address;
    node[i].address = node[j].address;
    node[j].address = temp;
    
    temp = node[i].data;
    node[i].data = node[j].data;
    node[j].data = temp;
}

void Reverse(NODE node[], int n, int k)
{
    int i, j, step;
    int totalReverNum = n / k;
    
    for(i = 1; i <= totalReverNum; i++)
    {
        step = 0;
        for(j = 0; j < k/2; j++)
        {
            Swap2(node, (k*(i-1)+1)+step, k*i-step); // 如果想提速,可以把乘法在调用Swap2之前算出来,但是这样会增加变量的个数,权衡之下如果不超时的话就不做修改了:~
            step++;
        }    
    }
    
    //遍历,修改next
    for(i = 1; i < n; i++)
    {
        node[i].next = node[i+1].address;
    }
    node[i].next = -1;
}

下面给出经典的利用三个指针变量进行反转的思路:

Ptr Reverse(Ptr head, int K) // head是一个无用的头节点
{
    cnt = 1;
    new = head->next;
    old = new->next;
    while(cnt < K)
    {
        tmp = old->next;
        old->next = new;
        new = old;
        old = tmp;
        cnt++;
    }
    head->next->next = old;
    return new;
}
02-线性结构3. Pop Sequence (25)
Given a stack which can keep M numbers at most. Push N numbers in the order of 1, 2, 3, ..., N and pop randomly. You are supposed to tell if a given sequence of numbers is a possible pop sequence of the stack. For example, if M is 5 and N is 7, we can obtain 1, 2, 3, 4, 5, 6, 7 from the stack, but not 3, 2, 1, 7, 5, 6, 4.

Input Specification:

Each input file contains one test case. For each case, the first line contains 3 numbers (all no more than 1000): M (the maximum capacity of the stack), N (the length of push sequence), and K (the number of pop sequences to be checked). Then K lines follow, each contains a pop sequence of N numbers. All the numbers in a line are separated by a space.

Output Specification:

For each pop sequence, print in one line "YES" if it is indeed a possible pop sequence of the stack, or "NO" if not.

Sample Input:
5 7 5
1 2 3 4 5 6 7
3 2 1 7 5 6 4
7 6 5 4 3 2 1
5 6 4 3 7 2 1
1 7 6 5 4 3 2
Sample Output:
YES
NO
NO
YES
NO
// 这个题还是有些难度的,类比于火车进站的问题,需要考虑的点比较多,感觉本质上还是一道模拟题。
#include<stdio.h>
#define MAXN 1000
int stack[MAXN+10];
int arr[MAXN+10]; 
int main(void)
{
    int m, n, k, i, j;
    int x, y, top; // x模拟进栈序列,y模拟出栈序列,top代表栈顶
    
    scanf("%d%d%d", &m, &n, &k);
    
    for(i = 1; i <= k; i++)
    {
        for(j = 1; j <= n; j++)
            scanf("%d", &arr[j]);
            
        y = 1;
        top = 0;
        for(x = 1; x <= n; x++) // n个数字逐个入栈
        {    
            stack[++top] = x;
            if(top > m)
                break;
            
            while(top > 0 && arr[y] == stack[top])
            {
                y++;
                top--;
            }        
        }
        
        if(x <= n || top > 0)
            printf("NO\n");
        else
            printf("YES\n");
    }
    
    
    return 0;
}

上面是数组模拟的,下面我写了一个真实版的栈模拟:

#include<stdio.h>
#include<malloc.h>
typedef struct Node
{
    int data;
    struct Node * next;
}NODE, *PNODE;

typedef struct Stack
{
    PNODE pHead;
    int sumItem;
}STACK, *PSTACK;

void MakeStack(PSTACK pS);
int IsEmpty(PSTACK pS);
void Push(PSTACK pS, int value);
int Pop(PSTACK pS);
int Peek(PSTACK pS);
int SumItem(PSTACK pS);
void Clear(PSTACK pS);

int arr[1010];
int main(void)
{    
    int m, n, k, i, j;
    int x, y; // x模拟进栈序列,arr[y]模拟出栈序列
    STACK S;
        
    scanf("%d%d%d", &m, &n, &k);
    
        
    MakeStack(&S);
    for(i = 1; i <= k; i++)
    {
        for(j = 1; j <= n; j++)
            scanf("%d", &arr[j]);
            
        y = 1; 
        Clear(&S);
        for(x = 1; x <= n; x++) // n个数字逐个入栈
        {    
            Push(&S, x);
            if(SumItem(&S) > m)
                break;
            
            while(!IsEmpty(&S) && arr[y] == Peek(&S))
            {
                // printf("haha, I am here.\n"); // test
                y++;
                Pop(&S);
            }        
        }
        
        if(x <= n || !IsEmpty(&S))
            printf("NO\n");
        else
            printf("YES\n");
    }
    
    
    
    return 0;
}

void MakeStack(PSTACK pS)
{
    pS->pHead = NULL;
    pS->sumItem = 0;
}

int IsEmpty(PSTACK pS)
{
    if(pS->pHead == NULL)
        return 1;
    else
        return 0;
}

void Push(PSTACK pS, int value)
{
    PNODE pTemp;
    
    pTemp = pS->pHead;
    pS->pHead = (PNODE)malloc(sizeof(NODE));
    pS->pHead->data = value;
    pS->pHead->next = pTemp;
    pS->sumItem++;    
}

int Pop(PSTACK pS) // 调用前需要调用IsEmpty来判断栈是否为空,在主程序中的短路原则体现了这一点,因此Pop函数中省略了判空这一步
{
    int value;
    PNODE pTemp;

    value = pS->pHead->data;
    pTemp = pS->pHead;
    pS->pHead = pS->pHead->next;
    pS->sumItem--;
    free(pTemp);
    return value;
}

int Peek(PSTACK pS) // 调用前需要调用IsEmpty来判断栈是否为空,没有判空的原因同上
{
    return pS->pHead->data;
}

int SumItem(PSTACK pS)
{
    return pS->sumItem;
}

void Clear(PSTACK pS)
{
    while(!IsEmpty(pS))
        Pop(pS);
}

 

(END_XPJIANG)