深信服2018校园招聘C++工程师编程题 - 题解

本文解析了深信服校园招聘中的编程题目,包括堆排序、单链表冒泡排序、二进制位反序、字符串匹配及围棋气的计算等。每道题目都提供了详细的解题思路和代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

深信服2017的校园招聘的题目和这次的几乎一样,不知道贵公司是什么样的想法。做过2017的题目的同学应该会比较占优势。题目不难,比较考验编程的技巧与准确度。

第一题:堆排序

题目:

函数heap_sort使用堆排序的方法对数组arr进行排序,排序后的数据为降序,相关的代码如下,请补充确实的部分。

//  调整为小顶堆
static void heap_arrange(int arr[], int cur, int cnt)  //调整为小顶堆
{
    int heaptop_val = arr[cur]; //堆顶的值
    while (cur < cnt) {
        int left = 2 * cur + 1;
        int right = 2 * cur + 2;
        int min = -1;
        int min_val = ________;
        if (left < cnt && arr[left] < min_val) { //检查是否比左节点大
            min = left;
            min_val = arr[left];
        }
        if (right < cnt && arr[right] < min_val) {//检查是否比右节点大
            min = right;
        }
        if (min == ________)
            break;
        arr[cur] = ________;
        cur = ________;
    }
    arr[cur] = ________;
}

解析:

堆排序的原理就是树上的插入排序,因此,堆排序的原理还是要准确理解的,这样才能填出来,既然是插入排序,那么,min_val就一直是heaptop_valmin_val与左右两个孩子比较得出最小的那个元素,如果最小的元素还是heaptop_val那么min的值就没变,仍然是-1,这个时候插入排序结束,找到了插入的位置就跳出;否则的话就把左右孩子最小的那个结点赋值给当前节点,故arr[cur] = arr[min],更新当前节点cur = min;最后,把heaptop_val调到要插入的位置,即arr[cur] = heaptop_val

代码:

//  调整为小顶堆
static void heap_arrange(int arr[], int cur, int cnt)  //调整为小顶堆
{
    int heaptop_val = arr[cur]; //堆顶的值
    while (cur < cnt) {
        int left = 2 * cur + 1;
        int right = 2 * cur + 2;
        int min = -1;
        int min_val = heaptop_val;
        if (left < cnt && arr[left] < min_val) { //检查是否比左节点大
            min = left;
            min_val = arr[left];
        }
        if (right < cnt && arr[right] < min_val) {//检查是否比右节点大
            min = right;
        }
        if (min == -1)
            break;
        arr[cur] = arr[min];
        cur = min;
    }
    arr[cur] = heaptop_val;
}

第二题:单链表冒泡排序

题目:

请实现list_sort,使用冒泡法将head指向的链表按val的值大小排成升序。

struct node {
    int val;
    struct node *next;
};

static void list_sort(struct node *head)
{

}

解析:

冒泡法大家都很熟悉,单链表来实现无非就是考到链表的基本操作,但是这里我们简化一下代码,也就是说,我们是采用交换两结点的值的做法而不是交换两个结点。

冒泡法有两个循环,最里面的循环是排序用的,而最外面的循环是排序需要的趟数,排序的趟数也就是链表的长度减一(排这么多趟一定可以排好序,但是不一定需要这么多);

这样一来就要求链表的长度,不好,注意到,如果排一趟序无可交换的元素,那么就说明链表已经排好序了,所以,利用这个原理可以设置一个标志变量f来维护一趟排序中是否有元素的交换,一趟排序后判一下f就可以知道是否跳出最外层的循环.

代码:

static void list_sort(struct node *head)
{
    //TODO:
    while (true) {
        int f = true;
        struct node * p = head;
        for (;p && p->next; p = p->next)
            if (p->val > p->next->val) {
                f = false;
                int tmp = p->val;
                p->val = p->next->val;
                p->next->val = tmp;
            }
        if (f)
            break;
    }
}

第三题:二进制位反序

题目:

编写函数reverse,将val(32位无符号整数)的二进制位反序,比如,如果val的二进制表示为1011000011111111,反序后val的二进制表示为1111111100001101

unsigned int reverse(unsigned int num)
{

}

解析:

做法很多,我的做法是把一边去掉最后一位数,一边生成反序后的十进制数。

代码:

unsigned int reverse(unsigned int num)
{
    //TODO:
    unsigned int ret = 0;
    for (int i = 0; i < 32; i++, num /= 2)
        ret = ret * 2 + num % 2;
    return ret;
}

第四题

题目:

函数match检查字符串str是否匹配模板pattern,匹配则返回0,否则返回-1

模板支持普通字符(a-z0-9A-Z)及通配符?*,普通字符匹配该字符本身,?匹配任意一个字符,*匹配任意多个字符。比如字符串abc对下述模板的匹配结果为:

模板-结果
abc0
a*0
a*c0
a*b-1
ab?0
a?-1

请完成该函数代码:

int match(const char *str, const char *pattern)
{

}

解析:

由于数据不大,故可以暴力递归解决,递归的终止条件是:

  • strlen(str)等于0,并且strlen(pattern)等于0,这时匹配成功;
  • strlen(str)strlen(pattern)有且只有一个为0,这时匹配失败。

如果strlen(str)strlen(pattern) 都不为0,那么继续递归:

  • pattern[0]?,那么就判断pattern + 1str + 1是否匹配;
  • pattern[0]*,那么判断pattern + 1str + i( 0<=i<strlen(str) 0 <= i < s t r l e n ( s t r ) )里面是否有一个匹配,只要有一个匹配,那么就匹配了,如果所有的都不匹配,那么就不匹配了;
  • pattern[0]为字母或数字,那么就判断str[0]pattern[0]是否相等,如果不相等就不匹配,如果相等,那么还要判断pattern + 1str + 1是否匹配。

这个题还要注意一点,题目给出的输入函数会把\n也会加入到字符串中,因此可以先把\n去掉,不去掉也可以,那么判断pattern[0]的时候就要注意顺序,先判断*?

代码:

int match(const char *str, const char *pattern)
{
    //TODO:
    int str_len = strlen(str), pattern_len = strlen(pattern);
    if (!str_len && !pattern_len)
        return 0;
    if (!pattern_len || !str_len)
        return -1;
    if (pattern[0] == '*') {
        for (int i = 0; str[i]; i++)
            if (0 == match(str + i, pattern + 1))
                return 0;
        return -1;
    } else if (pattern[0] == '?') {
        return match(str + 1, pattern + 1);
    } else {
        return pattern[0] == str[0] ? match(str + 1, pattern + 1) : -1;
    }
}

DIY数据:

// input
abcd
*********************
// output
match

第五题:围棋的“气”

题目:

函数calc计算围棋盘位置(x,y)处的棋子还有多少口气。

某个位置处的棋子还有多少口气的计算方法(简化计算):从该位置出发,向四个方向遍历,允许拐弯,但不允许走斜线,如果遇到边线和对方的棋子,则认为不能继续往前走。遍历完成后统计遍历过程中遇到的未落子的位置个数,该位置个数即出发点棋子的气的数目。

解析:

首先,这个简化计算描述就不清楚,注意这句话:如果遇到边线和对方的棋子,则认为不能继续往前走,那么遇到自己的棋子怎么办呢?这里值得思考一下;

如果遇到边线和对方的棋子和自己的棋子,则认为不能继续往前走,那么广搜一下,看看目标位置能到的位置有多少个,但是我只过了 66.6% 66.6 % 的数据,不知道哪里出了问题也不知道我是不是理解错题目了,于是,我计算了下围棋真正的气

首先找到该棋子的连通块,然后统计连通块外围棋子的个数就是该棋子的气。

找连通块我也没有用广搜,用的是一种扩散的想法,代码类似于这样子:往目标棋子滴一滴墨水,然后一秒钟后就会往外扩散,然后下一秒往外扩散,直到扩散不了。 具体实现看代码。

代码:

int calc(struct weiqi *wq, int y, int x)
{
    //TODO:
    if (wq->board[x][y] == NONE)
        return -1;
    enum color nowChess = wq->board[x][y];

    int dirx[] = {0, 0, 1, -1};
    int diry[] = {1, -1, 0, 0};
    int used[19][19] = {0};
    used[x][y] = 1;
    while (true) {
        int f = 0;
        for (int i = 0; i < 19; i++) {
            for (int j = 0; j < 19; j++) {
                if (used[i][j]) {
                    for (int k = 0; k < 4; k++) {
                        int tx = i + dirx[k];
                        int ty = j + diry[k];
                        if (tx >= 0 && tx < 19 && ty >= 0 && ty < 19 &&
                            wq->board[tx][ty] == nowChess && !used[tx][ty])
                            used[tx][ty] = 1, f = 1;
                    }
                }
            }
        }
        if (!f)
            break;
    }
    int ans = 0;
    for (int i = 0; i < 19; i++) {
        for (int j = 0; j < 19; j++) {
            if (used[i][j] == 1) {
                for (int k = 0; k < 4; k++) {
                    int tx = i + dirx[k];
                    int ty = j + diry[k];
                    if (tx >= 0 && tx < 19 && ty >= 0 && ty < 19 &&
                        wq->board[tx][ty] == NONE && used[tx][ty] != 1)
                        used[tx][ty] = 2;
                }
            }
        }
    }
    for (int i = 0; i < 19; i++) {
        for (int j = 0; j < 19; j++) {
            ans += (used[i][j] == 2);
        }
    }
    return ans;
}

DIY数据:

// input
0000000000000000000
0011100000000000000
0001000000000000000
0001111000000000000
0000001000000000000
0000000000000000000
0000000000000000000
0000000000000000000
0000000000000000000
0000000000000000000
0000000000000000000
0000000000000000000
0000000000000000000
0000000000000000000
0000000000000000000
0000000000000110000
0000000000000000000
0000000000000000000
0000000000000000000
2,1
// output
16

五个题完整代码:

一、

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
static void heap_arrange(int arr[], int cur, int cnt);

static int heap_verify(int arr[], int cnt)
{
    int i;
    for (i = 0; i < cnt / 2; ++i) {
        int lhs = 2 * i + 1;
        int rhs = 2 * i + 2;

        if (lhs < cnt && arr[i] > arr[lhs]) {
            fprintf(stderr, "arr[%d]:%d > arr[%d]:%d\n", i, arr[i], lhs, arr[lhs]);
            return -1;
        }
        if (rhs < cnt && arr[i] > arr[rhs]) {
            fprintf(stderr, "arr[%d]:%d > arr[%d]:%d\n", i, arr[i], rhs, arr[rhs]);
            return -1;
        }
    }
    return 0;
}

static void heap_print(int arr[], int cnt)
{
    int layer = 0, num = 0;
    for (layer = 0; num < cnt; ++layer) {
        int i = 0;
        for (i = 0 ; i < (1 << layer) && num < cnt ; ++i)
            printf("%3d ", arr[num++]);
        printf("\n");
    }
}
static void heap_sort(int arr[], int cnt)
{
    int i;

    printf("origin:\n");
    heap_print(arr, cnt);
    //  建堆
    for (i = cnt / 2 - 1; i >= 0; --i) {
        heap_arrange(arr, i, cnt);
    }
    printf("make heap:\n", i);
    heap_print(arr, cnt);
    assert(heap_verify(arr, cnt) == 0);
    for (i = cnt - 1; i > 0; --i) {
        int tmp;
        tmp = arr[0];
        arr[0] = arr[i];
        arr[i] = tmp;
        printf("sort i=%d\n", i);
        heap_print(arr, cnt);
        heap_arrange(arr, 0, i);
        heap_print(arr, cnt);
        assert(heap_verify(arr, i) == 0);
    }
    printf("sorted:\n");
    heap_print(arr, cnt);
}
static int input(int **arr, int *size)
{
    int i;
    int ret;

    ret = fscanf(stdin, "%d\n", size);
    if (ret != 1)
        return -1;
    *arr = (int *)malloc(sizeof(int) * (*size));
    for (i = 0; i < *size; ++i) {
        fscanf(stdin, "%d ", &(*arr)[i]);
    }
    return 0;
}

int main(int argc, char *argv[])
{
    int *arr = NULL;
    int cnt = 0;
    int i;

    if (input(&arr, &cnt) < 0) {
        fprintf(stderr, "input error\n");
        return 0;
    }
    heap_sort(arr, cnt);
    return 0;
}
//  调整为小顶堆
static void heap_arrange(int arr[], int cur, int cnt)  //调整为小顶堆
{
    int heaptop_val = arr[cur]; //堆顶的值
    while (cur < cnt) {
        int left = 2 * cur + 1;
        int right = 2 * cur + 2;
        int min = -1;
        int min_val = heaptop_val;
        if (left < cnt && arr[left] < min_val) { //检查是否比左节点大
            min = left;
            min_val = arr[left];
        }
        if (right < cnt && arr[right] < min_val) {//检查是否比右节点大
            min = right;
        }
        if (min == -1)
            break;
        arr[cur] = arr[min];
        cur = min;
    }
    arr[cur] = heaptop_val;
}

二、

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

struct node {
    int val;
    struct node *next;
};

static void list_sort(struct node *head);

struct node *list_create(int arr[], int size)
{
    struct node *head = NULL;
    int i;
    for (i = size - 1; i >= 0; --i) {
        struct node *p = (struct node *)malloc(sizeof(struct node));

        p->val = arr[i];
        p->next = head;
        head = p;
    }
    return head;
}
static void list_print(struct node *head)
{
    for (; head; head = head->next) {
        printf("%d", head->val);
        if (head->next)
            printf(" ");
    }
    printf("\n");
}
static void list_free(struct node *head)
{
    struct node *next;
    while (head) {
        next = head->next;
        free(head);
        head = next;
    }
}
static int input(int **arr, int *size)
{
    int i;
    int ret;

    ret = fscanf(stdin, "%d\n", size);
    if (ret != 1)
        return -1;
    *arr = (int *)malloc(sizeof(int) * (*size));
    for (i = 0; i < *size; ++i) {
        fscanf(stdin, "%d ", &(*arr)[i]);
    }
    return 0;
}

int main(int argc, char *argv[])
{
    struct node *head;
    int *arr = NULL;
    int size = 0;

    if (input(&arr, &size) < 0) {
        fprintf(stderr, "input error\n");
        return 0;
    }
    head = list_create(arr, size);
    list_sort(head);
    list_print(head);
    list_free(head);
    free(arr);
    return 0;
}

static void list_sort(struct node *head)
{
    //TODO:
    while (true) {
        int f = true;
        struct node * p = head;
        for (;p && p->next; p = p->next)
            if (p->val > p->next->val) {
                f = false;
                int tmp = p->val;
                p->val = p->next->val;
                p->next->val = tmp;
            }
        if (f)
            break;
    }
}

三、

#include <stdio.h>
#include <string.h>

unsigned int reverse(unsigned int num)
{
    //TODO:
    unsigned int ret = 0;
    for (int i = 0; i < 32; i++, num /= 2)
        ret = ret * 2 + num % 2;
    return ret;
}

int main(int argc, char *argv[])
{
    unsigned int num = 0;
    unsigned int ret = 0;

    if (1 != fscanf(stdin, "0x%x", &num)) {
        fprintf(stderr, "input error\n");
        return 0;
    }
    ret = reverse(num);
    printf("%08x\n", ret);
    return 0;
}

四、

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <malloc.h>

int match(const char *str, const char *pattern)
{
    //TODO:
    int str_len = strlen(str), pattern_len = strlen(str);
    if (!str_len && !pattern_len)
        return 0;
    if (!pattern_len || !str_len)
        return -1;
    if (pattern[0] == '*') {
        for (int i = 0; str[i]; i++)
            if (0 == match(str + i, pattern + 1))
                return 0;
        return -1;
    } else if (pattern[0] == '?') {
        return match(str + 1, pattern + 1);
    } else {
        return pattern[0] == str[0] ? match(str + 1, pattern + 1) : -1;
    }
}

int input(char **src, char **ptn)
{
    char buf[10240];

    *src = NULL;
    *ptn = NULL;
    if (fgets(buf, sizeof(buf), stdin) == 0)
        goto failed_;
    *src = strdup(buf);
    if (fgets(buf, sizeof(buf), stdin) == 0)
        goto failed_;
    *ptn = strdup(buf);
    return 0;
    failed_:
    if (*src)
        free(*src);
    if (*ptn)
        free(*ptn);
    *src = NULL;
    *ptn = NULL;
    return -1;
}

int main(int argc, char *argv[])
{
    char *src = NULL;
    char *ptn = NULL;

    if (input(&src, &ptn) < 0) {
        fprintf(stderr, "error\n");
        return 0;
    }

    if (match(src, ptn) == 0) {
        printf("match\n");
    } else {
        printf("unmatch\n");
    }
    return 0;
}

五、

#include <stdio.h>
#include <string.h>

enum color {
    NONE, WHITE, BLACK,         //棋子颜色,NONE表示未落子
};
struct weiqi {
    enum color board[19][19];   //棋盘上每个位置的落子
};

int calc(struct weiqi *wq, int y, int x)
{
    //TODO:
    if (wq->board[x][y] == NONE)
        return -1;
    enum color nowChess = wq->board[x][y];

    int dirx[] = {0, 0, 1, -1};
    int diry[] = {1, -1, 0, 0};
    int used[19][19] = {0};
    used[x][y] = 1;
    while (true) {
        int f = 0;
        for (int i = 0; i < 19; i++) {
            for (int j = 0; j < 19; j++) {
                if (used[i][j]) {
                    for (int k = 0; k < 4; k++) {
                        int tx = i + dirx[k];
                        int ty = j + diry[k];
                        if (tx >= 0 && tx < 19 && ty >= 0 && ty < 19 &&
                            wq->board[tx][ty] == nowChess && !used[tx][ty])
                            used[tx][ty] = 1, f = 1;
                    }
                }
            }
        }
        if (!f)
            break;
    }
    int ans = 0;
    for (int i = 0; i < 19; i++) {
        for (int j = 0; j < 19; j++) {
            if (used[i][j] == 1) {
                for (int k = 0; k < 4; k++) {
                    int tx = i + dirx[k];
                    int ty = j + diry[k];
                    if (tx >= 0 && tx < 19 && ty >= 0 && ty < 19 &&
                        wq->board[tx][ty] == NONE && used[tx][ty] != 1)
                        used[tx][ty] = 2;
                }
            }
        }
    }
    for (int i = 0; i < 19; i++) {
        for (int j = 0; j < 19; j++) {
            ans += (used[i][j] == 2);
        }
    }
    return ans;
}
int input(struct weiqi *wq, int *x, int *y)
{
    int row, col;
    int ret;
    char buf[80];

    for (row = 0; row < 19; ++row) {
        if (fgets(buf, sizeof(buf), stdin) == NULL)
            return -1;
        if (strlen(buf) < 19)
            return -1;
        for (col = 0; col < 19; ++col) {
            switch (buf[col]) {
                case '0':
                    wq->board[row][col] = NONE;
                    break;
                case '1':
                    wq->board[row][col] = WHITE;
                    break;
                case '2':
                    wq->board[row][col] = BLACK;
                    break;
                default:
                    return -1;
            }
        }
    }
    ret = fscanf(stdin, "%d,%d\n", x, y);
    if (ret != 2)
        return -1;
    for (row = 0 ; row < 19; ++row) {
        for (col = 0; col < 19; ++col) {
            fprintf(stderr, "%d ", wq->board[row][col]);
        }
        fprintf(stderr, "\n");
    }
    fprintf(stderr, "x = %d, y = %d\n", *x, *y);
    return 0;
}

int main()
{
    struct weiqi wq;
    int x = 0, y = 0;
    int cnt;

    memset(&wq, 0, sizeof(wq));
    if (input(&wq, &x, &y) < 0) {
        fprintf(stderr, "error!\n");
        return 1;
    }
    cnt = calc(&wq, x, y);

    printf("%d\n", cnt);
    return 0;
}
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值