编程练习 15.12.23~15.12.29


C POINTER

Write a C function to sort an array of five integer values in ascending order.

The function will accept two arguments– a pointer that points to the array and the array size. The function returns a pointer that points to the sorted array.
main.c如下

#include <stdio.h>
#include "sort.h"

int main() {
    int arr[5];
    int j;
    for (j = 0; j < 5; j++) {
        scanf("%d", &arr[j]);
    }
    int *p = sortAsc(arr, 5);
    int i;
    for (i = 0; i < 5; i++)
        printf("%d ", *(p+i));
    printf("\n");
    return 0;
}

读题

写个头文件,对传进来指针所指数组的五个元素进行排序
难度不大,写个冒泡就可以了

my answer

int * sortAsc(int * a, int n) {
    int i, j, temp;
    for (i = 0; i <= 3; i++)
    for (j = 4; j >= i; j--) {
        if (a[j] < a[j - 1]) {
            temp = * (a + j);
            * (a + j) = * (a + j - 1);
            * (a + j - 1) = temp;
        }
    }
    return a;
}

the standard answer

#ifndef sort_h
#define sort_h

#include <stdio.h>
int *sortAsc(int *p, int n) {
    int i, j;
    for (i = 0; i < n; i++)
        for (j = i + 1; j < n; j++)
            if (*(p + j) < *(p + i)) {
                int temp = *(p + j);
                *(p + j) = *(p + i);
                *(p + i) = temp;
            }
    return p;
}

#endif /* sort_h */

反馈

You should implement two function swap() and subMiddle() .

swap: exchange two number

void swap(int *i, int *j) {

}

subMiddle:link the first node and the third node.return the address of the second node.you need not to free the second node which will be freed in main function.

Node* subMiddle(Node* h) {

return ..;
}

format:You don’t need to think about the output.

For example


[Input]

1 2
3 4 5

[Output]

2 1
3 5


main.c:

#include <stdio.h>
#include <malloc.h>
#include "function.h"

int main() {
    int a, b;

    scanf("%d%d", &a, &b);
    swap(&a, &b);  // 交换a,b变量的值
    printf("%d %d\n", a, b);

    // 链表头部、尾部、用于存储malloc得到Node地址的临时指针
    Node *head, *tail, *temp;
    head = tail = NULL;

    // 创建长度为3的链表
    int t = 3;
    while (t--) {
        // 这里写上强制类型转换也能过google风格
        // temp = (Link)malloc(sizeof(Node));
        temp = (Node*)malloc(sizeof(Node));
        scanf("%d", &temp->num);
        //  将每个节点的下个指针置为NULL
        temp->next = NULL;
        if (!head) {  // 第一个节点
            head = tail = temp;
        } else {  // 后续节点
            tail->next = temp;
            tail = tail->next;
        }
    }

    temp = subMiddle(head);  // 移除中间节点
    free(temp);  // 释放内存中间节点内存

    temp = head;
    while (temp) {  // 遍历输出
        printf("%d ", temp->num);
        temp = temp->next;
    }

    while (head) {  // 释放移除节点后的链表所占内存
        temp = head;
        head = head->next;
        free(temp);
    }

    return 0;
}

Node.h:

#ifndef __NODE_H__
#define __NODE_H__

typedef struct Node {
    int num;
    struct Node* next;
} Node;

#endif

读题

my answer

function.h:

void swap(int *i, int *j) {
    int temp;
    temp = * i;
    * i = * j;
    * j = temp;
}

Link subMiddle(Link head) {
    Link p1 = head -> next;
    head -> next = p1 -> next;
    return p1;
}

the standard answer

#ifndef __FUNCTION_H__
2.#define __FUNCTION_H__
3.#include "Node.h"
4. 
5.void swap(int *i, int *j) {
6.    int temp = *i;
7.    *i = *j;
8.    *j = temp;
9.}
10. 
11.Node* subMiddle(Node* h) {
12.    Node* temp = h->next;
13.    h->next = temp->next;
14.    return temp;
15.}
16. 
17.#endif

反馈

Somethings about Floors

题目内容:一个楼梯有N级(N >=0), 每次走1级或2级, 从底走到顶一共有多少种走法?

输入要求:只有一行输入,并且只有一个数N(如果N > 20,则N = N%21,即保证N的范围控制为:0 <= N <= 20,当取模后的值为0时,输出1),代表这个楼梯的级数。

输出要求:只有一行,输出从底到顶的走法,后面有换行。

参考样例:

输入: 3

输出: 3

Hint:
问题分解。

读题

最后一步可能是两级到达 也可能是一级到达
所以n级所有方法 = (n-1)级所有方法 + (n - 2) 级所有方法

my answer

// by hling so
#include <stdio.h>
long num(long n) {
    if (n == 1 || n == 2)
        return n;
    long step1 = 1, step2 = 2, result = 0;
    long temp = 3;
    for (temp = 3; temp <= n; temp++) {
        result = step1 + step2;
        step1 = step2;
        step2 = result;
    }
    return result;
}
int main() {
    long m, n;
        scanf("%ld", &n);
        n = n % 21;
        if (n == 0)
        printf("1\n");
        else
        printf("%ld\n", num(n));
    return 0;
}

the standard answer

// from younglee
// solve the problem in two different way, with recursion and no recursion.
#include<stdio.h>
#include<string.h>
#define N 100

#define RECUR 1
#define MODE 0

int dealWithRecursion(int f);
int dealWithNoRecursion(int f);
// to save the result.
int arr[N];

int main(void) {
    int floor;
    scanf("%d", &floor);
    floor %= 21;
    if (MODE == RECUR) {
        printf("%d\n", dealWithRecursion(floor));
    } else {
        memset(arr, 0, sizeof(arr));
        printf("%d\n", dealWithNoRecursion(floor));
    }
    return 0;
}

int dealWithRecursion(int f) {
    if (f == 1 || f == 0) return 1;
    return (dealWithRecursion(f - 1) + dealWithRecursion(f - 2));
}

int dealWithNoRecursion(int f) {
    if (arr[f] != 0) return arr[f];
    int result;
    if (f == 0 || f == 1) result = 1;
    else result = dealWithNoRecursion(f - 1) + dealWithNoRecursion(f - 2);
    arr[f] = result;
    return result;
}

反馈

做过的,斐波那契数列.
递归比较易懂,但耗时
循环也不难写.

ListAgain

实现一个链表,可以很好地练习指针的用法。

实现一个环形的双向链表,链表的每个节点都保存三个信息,当前节点的值value,前一个节点的指针prev,后一个节点的指针next。因为是环形的,所以最后一个节点的next指向第一个节点,而第一个节点的prev指向最后一个节点

如果只存在一个节点,那么这个节点的prev和next都会指向这个节点本身。

然而实现这样一个链表难度很大。所以我们来简化一下这个任务。

我已实现出链表添加元素的部分,现在由你实现一个print函数,

样例输入:
5
1 2 3 4 5
样例输出
5
4
3
2
1

Hint:
print函数中,你需要从first开始,沿着next指针的顺序,依次输出所有节点的值,每输出一个数都换一次行。

同时,在print函数里要把所有为链表动态申请的内存空间释放掉。(可以两步一起完成,也可以分开完成)
main.c:

#include<stdio.h>
#include"func.h"
node* add(node* first, int value) {
    if (first == NULL) {
        first = (node*)malloc(sizeof(node));
        first->prev = first->next = first;
        first->value = value;
        return first;
    }
    node* p = first->prev;
    node* q = first;
    node* tmp = (node*)malloc(sizeof(node));
    tmp->value = value;
    tmp->next = q;
    tmp->prev = p;
    p->next = tmp;
    q->prev = tmp;
    first = tmp;
    return first;
}
int main() {
    int n;
    int y, i;
    scanf("%d", &n);
    node* first = NULL;
    for (i = 1; i <= n; i++) {
        scanf("%d", &y);
        first = add(first, y);
    }
    print(first);
    return 0;
}

node.h

#ifndef __NODE_H__
#define __NODE_H__
typedef struct node {
    int value;
    struct node* prev;
    struct node* next;
}node;
#endif

读题

my answer

function.h :

#ifndef __FUNCTION_H__
#define __FUNCTION_H__
#include"node.h"
#include<malloc.h>

void print(struct node* first) {
    struct node* current, * last;
    current = first;
    (first->prev)->next = NULL;
    while (current) {
        printf("%d\n", current->value);
        last = current;
        current = current->next;
        free(last);
    }
}
#endif

the standard answer

#ifndef __FUNCTION_H__
#define __FUNCTION_H__
#include"node.h"
#include<malloc.h>
void print(node* first) {
    if (first == NULL) return;
    node* p = first->prev;
    p->next = NULL;
    p = first;
    while (p != NULL) {
        printf("%d\n", p->value);
        node* tmp = p;
        p = p->next;
        free(tmp);
    }
}
#endif

反馈

sizeof & offsetof (for hw)

定义一个结构体类型S包含6个变量。实例化一个S,输出此实例在内存中所占空间大小(使用sizeof),输出6个变量分别所占内存大小之和以及6个变量在内存中距离此实例的首地址的长度(使用offsetof)。

注意6个变量的顺序如下:

char a;
short a2;
int b[10];
float c;
double d;
short d2;

根据所输出内容理解struct中不同类型的变量在内存中的组织形式,同时了解为何a2和d2所占用空间存在差异。

Hint:
可能要用到 stddef.h

我也知道可以helloworld式的解决,但希望通过这个例子让同学们进一步加深理解。

另外可参考http://blog.csdn.net/callinglove/article/details/46534883

读题

my answer

#include<stdio.h>
#include<stddef.h>
typedef struct S {
    char a;
    short a2;
    int b[10];
    float c;
    double d;
    short d2;
}S;
int main() {
    struct S eg;
    printf("%d\n\n", sizeof(eg));
    printf("%d\n%d\n%d\n%d\n%d\n%d\n\n", sizeof(eg.a), sizeof(eg.a2),
    sizeof(eg.b), sizeof(eg.c), sizeof(eg.d), sizeof(eg.d2));
    printf("%d\n%d\n%d\n%d\n%d\n%d\n", offsetof(S, a), offsetof(S, a2),
    offsetof(S, b), offsetof(S, c), offsetof(S, d), offsetof(S, d2));
    return 0;
}

the standard answer

#include<stdio.h>
#include<stddef.h>
struct s  {
    char a;
    short a2;
    int b[10];
    float c;
    double d;
    short d2;
};

int main() {
    struct s k;
    printf("%d\n", sizeof(k));
    printf("\n");
    printf("%d\n", sizeof(k.a));
    printf("%d\n", sizeof(k.a2));
    printf("%d\n", sizeof(k.b));
    printf("%d\n", sizeof(k.c));
    printf("%d\n", sizeof(k.d));
    printf("%d\n", sizeof(k.d2));
    printf("\n");
    printf("%d\n", offsetof(struct s, a));
    printf("%d\n", offsetof(struct s, a2));
    printf("%d\n", offsetof(struct s, b));
    printf("%d\n", offsetof(struct s, c));
    printf("%d\n", offsetof(struct s, d));
    printf("%d\n", offsetof(struct s, d2));
    return 0;
}

反馈

offsetof 中要用原

二叉树链表实现(for hw)

使用链表实现二叉树的构造并完成中序遍历。

首先在头文件中定义结点结构体如下:

typedef struct node {

int x;

struct node* left;

struct node* right;

} BN;

其次要实现两个函数,函数buildTree通过读入一串整数以层次优先从左到右的方式构建一个二叉树,函数outputTree输出此树的中序遍历。两个函数的原型如下:

void buildTree(BN** rootptr);

void outputTree(BN* root);

输入:N个正整数,1<=N<=30,以空格间隔,以-1结束。注意-1不包含在此树的结构中,只是作为输入结束的符号。

输出:一行按照中序遍历排列的正整数,以空格间隔,最后一个输出的元素后仍然有空格,且没有换行

注意:main函数已经给出,并且在其中给出了树的根节点的指针以及整棵树free的过程,buildTree函数内所有的结点应以malloc形式生成,如果一个结点没有左儿子或者右儿子,则相应的指针应该等于NULL。

Sample:

input:

1 2 3 4 5 6 7 8 9 -1

output:

8 4 9 2 5 1 6 3 7

Hint:
如果以层次优先从左向右构建二叉树的过程感觉有难度,可以参考main函数中释放所有结点空间的做法。思想就是使用一个“队列”数据结构存储要处理的指针。

关于前序中序后序遍历的知识请自行查找书本及网上相应内容进行学习。

main.c

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include"tree.h"
#define MAXI 50
int main() {
    BN* root;
    BN* que[MAXI];    /*used for free*/
    int head = 0;   /*head of que*/
    int tail = 1;   /*tail of que*/
    buildTree(&root);
    outputTree(root);
    /*the free procedure*/
    que[0] = root;
    while (head != tail) {
        if (que[head]->left != NULL) {
            que[tail] = que[head]->left;
            tail = (tail + 1) % MAXI;
        }
        if (que[head]->right != NULL) {
            que[tail] = que[head]->right;
            tail = (tail + 1) % MAXI;
        }
        free(que[head]);
        head = (head + 1) % MAXI;
    }
    return 0;
}

读题

my answer

tree.h

#include<stdio.h>
#include<malloc.h>
typedef struct node {
    int x;
    struct node* left;
    struct node* right;
} BN;
void buildTree(BN** rootptr) {
    int temp;
    BN* que[50];/*used for free*/
    int head = 0;   /*head of que*/
    int tail = 1;   /*tail of que*/
    *rootptr = malloc(sizeof(BN));
    que[0] = *rootptr;
    scanf("%d", &temp);
    que[head]->left = NULL;
    que[head]->right = NULL;
    que[head]->x = temp;
    for (scanf("%d", &temp); temp != -1; scanf("%d", &temp)) {
        que[head]->left = malloc(sizeof(BN));
        que[tail] = que[head]->left;
        que[tail]->left = NULL; que[tail]->right = NULL;
        que[tail]->x = temp;
        tail = tail + 1;
        scanf("%d", &temp);
        if (temp == -1) break;
        que[head]->right = malloc(sizeof(BN));
        que[tail] = que[head]->right;
        que[tail]->left = NULL; que[tail]->right = NULL;
        que[tail]->x = temp;
        tail = tail + 1;
        head = head + 1;
    }
}
void outputTree(BN* root) {
    if (root != NULL) {
        outputTree(root->left);
        printf("%d ", root->x);
        outputTree(root->right);
    }
}

the standard answer

#ifndef __TREELL__
#define __TREELL__
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAXINDEX 50
typedef struct node {
    int x;
    struct node* left;
    struct node* right;
} BN;
void buildTree(BN** root) {
    BN forStyle = {1, NULL, NULL};
    int temp;
    BN** que[MAXINDEX];
    int head = 0;
    int tail = 1;
    que[0] = root;
    scanf("%d", &temp);
    while (temp != -1) {
        *que[head] = malloc(sizeof(forStyle));
        (*que[head])->x = temp;
        que[tail] = &((*que[head])->left);
        tail = (tail + 1) % MAXINDEX;
        que[tail] = &((*que[head])->right);
        tail = (tail + 1) % MAXINDEX;
        head = (head + 1) % MAXINDEX;
        scanf("%d", &temp);
    }
    while (head != tail) {
        *que[head] = NULL;
        head = (head + 1) % MAXINDEX;
    }
}
void outputTree(BN* root) {
    if (root != NULL) {
        outputTree(root->left);
        printf("%d ", root->x);
        outputTree(root->right);
    }
}
#endif

反馈

Matrix(for hw)

Description

Given a N × N matrix A, whose element in the i-th row and j-th column Aij is an number that equals i2 + 100000 × i + j2 - 100000 × j + i × j, you are to find the M-th smallest element in the matrix.

Input

The first line of input is the number of test case.
For each test case there is only one line contains two integers, N(1 ≤ N ≤ 50,000) and M(1 ≤ M ≤ N × N). There is a blank line before each test case.

Output

For each test case output the answer on a single line.

Sample Input
12

1 1

2 1

2 2

2 3

2 4

3 1

3 2

3 8

3 9

5 1

5 25

5 10

Sample Output
3
-99993
3
12
100007
-199987
-99993
100019
200013
-399969
400031
-99939

Source

POJ.3685

POJ Founder Monthly Contest – 2008.08.31, windy7926778
Hint:

1.注意long long

2.2500000000个数直接排序的话是没有算法能在1秒内完成的

3.观察矩阵会发现固定j,元素的值会随i递增,因此如果我们知道了某个值K,可以对每一列采用二分查找的方法在O(NlogN)的时间内找出矩阵中有多少个数小于K

4.显然矩阵中小于K的元素的个数也是随K递增的,因此用跟3相同思想的某种方法可以使整个算法的时间复杂度维持在O(TNlogNlogL)以内,其中L是矩阵的值域大小

5.师兄只能提示到这里了←_←

6.注意long long,因为真的很容易出错所以提醒两遍

读题

先打个表看看这个矩阵是什么鬼压压惊

#include<stdio.h>
#define cal(i, j) i*i + 100000* i + j*j - 100000 * j + i *j
int main() {
    int i, j, n;
    scanf("%d", &n); 
    for(i = 1; i<= n; i++) {
        for(j = 1; j<= n; j++) {
            printf("%ld\t",  cal(i,j));
    } 
        printf("\n");
    }
    return 0;
}

(运行输入矩阵大小就可以看见啦啦啦~
也可以分别把i,j看做常数 对那个式子求导判断单调性= =
可以看出.
元素的大小每列(j不变),随着i变大而变大
每行看似有规律,实际当j大了之后就木有规律了 所以!
遍历j,并且对每j列进行二分查找.

整体思路是这样的:
1.先弄出最大数和最小数,(我用的是矩阵里的数, 答案貌似是..
2.二分查找, 看每次查找中间那个数mid是不是第m小的数
3.找到第m小的数之后输出

2.步细分:
要判断是不是第m小,就要知道当前的mid是第几小的数
也就是说,要求出比mid小的数有多少个
此处,对矩阵的元素进行比较.因为列是有单调性的,(有序)所以可以再次二分

也就是说,遍历每个j(列数), 通过对i二分查找算出该列有多少个数比mid小.

my answer

/* by hling so */
#include<stdio.h>
#define cal(i, j) i*i + 100000* i + j*j - 100000 * j + i *j
/*这里用宏定义 是因为 看到大神说 这样可以节省时间*/

int main() {
    int times;
    long long ans, n, m, left, right, mid, count, i, j;
    scanf("%d", &times);
    while (times--) {
        scanf("%ld%ld", &n, &m);
        left = cal(1, n);
        right = cal(n, 1);

        while (left <= right) {  /*对矩阵元素的二分查找*/
            mid = (left + right) >> 1;
            count = 0;
            for (j = 1; j <= n; j++) {  /* 枚举j */
                long long nleft = 1, nright = n;
                long long ncount = 0;

                while (nleft <= nright) {  /*对每列二分查找*/
                    long long nmid = (nleft + nright) >> 1;
                    long long midvalue = cal(nmid, j);
                    if (midvalue <= mid) {
                        ncount = nmid;
                        nleft = nmid + 1;
                    } else {
                        nright = nmid - 1;
                    }
                }
                count += ncount;
            }
            if (count >= m) {
                ans = mid;
                right = mid - 1;
            } else {
            left = mid + 1;
            }
        }
        printf("%ld\n", ans);
    }
    return 0;
}

the standard answer

#include <stdio.h>
#include <limits.h>

#define A(i, j) (((i) + (j)) * ((i) + (j)) - (i) * (j) + 100000LL * ((i) - (j)))

#define MAXn 50000LL
#define MAX 7500000000LL
#define MIN -2499849999LL

int main() {
    int T;
    long long min, max, mid, j, l, r, i, n, m, counter;

    for (scanf("%d", &T); T > 0; --T) {
        scanf("%lld%lld", &n, &m);
        min = MIN;
        max = MAX;

        do {
            mid = (min + max) >> 1;
            counter = 0;
            for (j = 1; j <= n; ++j) {
                l = 1;
                r = n;
                do {
                    i = (l + r) >> 1;
                    if (A(i, j) > mid)
                        r = i - 1;
                    else
                        l = i + 1;
                } while (l <= r);
                counter += l - 1;
            }
            if (counter < m)
                min = mid + 1;
            else
                max = mid - 1;
        } while (min <= max);
        printf("%lld\n", min);
    }
    return 0;
}

反馈

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值