考研复习 Day 36 | 习题--计算机网络 第七章 网络安全(下)、数据结构 排序算法(下)

注:以下习题参考 计算机网络(第八版)谢希仁 编著,数据结构与算法 王曙燕 主编。

一、计算机网络第7章 网络安全(下) 习题与解答

7-15 试述实现报文鉴别和实体鉴别的办法。

答案

类型 实现方法
报文鉴别 MAC(报文鉴别码)、数字签名、哈希函数(MD5、SHA)
实体鉴别 口令、挑战-应答、一次性密码、数字证书、生物特征

7-16 结合第5章图5-6计算UDP的检验和的例子,说明这种检验和不能用来鉴别报文。

答案

UDP检验和只检测传输错误(比特翻转),不能防止主动攻击。攻击者可修改数据并重新计算检验和,接收方无法区分是否被篡改,因此不能用于报文鉴别。


7-17 报文的机密性与完整性有何区别?什么是MD5?

答案

  • 机密性:防止信息泄露(加密)

  • 完整性:防止信息被篡改(哈希、MAC)

MD5:128位哈希函数,用于完整性校验,现已不安全。


7-18 什么是重放攻击?怎样防止重放攻击?

答案

重放攻击:攻击者记录并重复发送合法报文,欺骗接收方。

防范方法

  • 序号/时间戳

  • 一次性随机数(nonce)

  • 挑战-应答

  • 报文有效期限制


7-19 图 7-11 的鉴别过程也有可能被骗子利用。假定 A 发送报文和 B 联系,但不巧被骗子P 截获了,于是 P 发送报文给 A:"我是 B"。接着,A 就发送图 7-11 中的第一个报文"A,RA ",这里 R 是不重数。本来,P必须也发给 A 另一个不重数,以及发回使用两人共同拥有的密钥 KAB加密的 RA,即KAB(RA)。但P根本不知道 K,只好就发送同样的 RA 作为自己的不重数。A 收到 RA 后,发给 P 报文"KAB(RA)",P 仍然不知道密钥 KAB,也照样发回报文"KAB(RA)"。接着 A 就把一些报文发送给P了。虽然 P不知道密钥KB,但可以慢慢设法攻破。试问 A能否避免这样的错误?

答案

可以 。A 应验证对方返回的 RA 是否与自己发送的一致,并要求对方用共享密钥 KAB 加密。骗子无法提供正确响应,A 应立即终止连接。


7-20 什么是"中间人攻击"?怎样防止这种攻击?

答案

中间人攻击:攻击者在通信双方之间拦截并篡改报文,双方以为直接通信。

防范方法

  • 公钥证书(PKI)

  • 数字签名

  • 认证交换(如 TLS)


7-21 试讨论Kerberos协议的优缺点。

答案

优点 缺点
单点登录 需要时间同步
强安全性 密钥分发中心(KDC)是单点故障
支持双向认证 实现复杂

7-22 互联网的网络层安全协议族IPsec都包含哪些主要协议?

答案

  • AH(认证头):提供完整性、数据源认证

  • ESP(封装安全载荷):提供机密性、完整性、认证

  • IKE(密钥交换协议):建立安全关联(SA)


7-23 用户A和B使用IPsec进行通信。A需要向 B接连发送6个分组。是否需要每发送一个分组之前,都先建立一次安全关联SA?

答案

不需要。SA 建立后可供多个分组重复使用,直到过期或主动删除。


7-24 在图 7-18(b)中,公司总部和业务员之间先建立了 TCP 连接,然后使用 sec 进行通信。假定有一个 TCP报文段丢失了。后来在重传该序号的报文段时,相应的Psec安全数据报是否也要使用同样的 IPsec 序号呢?

答案

不能。IPsec序号用于防重放攻击,重传报文段应使用新序号,否则会被接收方丢弃。


7-25 试简述协议TLS的工作过程。

答案

  1. 客户端发送支持的加密算法、随机数

  2. 服务器返回证书、选择算法、随机数

  3. 客户端验证证书,生成预主密钥,用服务器公钥加密发送

  4. 双方计算会话密钥

  5. 开始加密通信


7-26 在图 7-21 中,假定在第一步,顾客(客户A)发送报文给经销商(服务器B)时,误将报文发送到一个骗子处,而骗子就接着冒充经销商继续下面的步骤。试问在报文交互到第几个步骤时,顾客可以发现对方并不是真正的经销商?

答案

在第 2 步(服务器返回证书或挑战时),顾客可发现证书无效或无法正确响应。


7-27 电子邮件的安全协议PGP主要都包含哪些措施?

答案

  • 数字签名(防篡改、防否认)

  • 加密(机密性)

  • Base64编码

  • 压缩

  • 公钥/私钥管理(Web of Trust)


7-28 试述防火墙的工作原理和所提供的功能。什么叫作网络级防火墙和应用级防火墙?

答案

类型 原理 功能
网络级防火墙 根据IP、端口过滤 包过滤、NAT
应用级防火墙 分析应用层协议 内容过滤、代理

功能:隔离内外网、访问控制、防攻击、日志审计。

二、数据结构第9章 排序(下) 算法设计题

(1) 使用监视哨实现直接插入排序

核心思路

将待排元素放在 A[0] 作为监视哨,减少比较次数。

C语言

复制代码
void insertSort(int A[], int n) {
    for (int i = 2; i <= n; i++) {
        A[0] = A[i];
        int j = i - 1;
        while (A[j] > A[0]) {
            A[j + 1] = A[j];
            j--;
        }
        A[j + 1] = A[0];
    }
}

C++

复制代码
void insertSort(vector<int>& A) {
    A.insert(A.begin(), 0);
    for (int i = 2; i < A.size(); i++) {
        A[0] = A[i];
        int j = i - 1;
        while (A[j] > A[0]) {
            A[j + 1] = A[j];
            j--;
        }
        A[j + 1] = A[0];
    }
    A.erase(A.begin());
}

(2) 判断完全二叉树是否为大顶堆

核心思路

检查所有非叶结点:A[i] >= A[2i] && A[i] >= A[2i+1]

C语言

复制代码
int isMaxHeap(int A[], int n) {
    for (int i = 1; i <= n / 2; i++) {
        if (2 * i <= n && A[i] < A[2 * i]) return 0;
        if (2 * i + 1 <= n && A[i] < A[2 * i + 1]) return 0;
    }
    return 1;
}

C++

复制代码
bool isMaxHeap(const vector<int>& A) {
    int n = A.size() - 1;
    for (int i = 1; i <= n / 2; i++) {
        if (2 * i <= n && A[i] < A[2 * i]) return false;
        if (2 * i + 1 <= n && A[i] < A[2 * i + 1]) return false;
    }
    return true;
}

(3) 编写算法,用基数排序方法将一组等长(含字母个数相同)的英文单词按字典顺序排列。

核心思路

  1. 从最后一个字母到第一个字母依次排序

  2. 每一轮按当前字母分配到26个桶中

  3. 再按桶顺序收集回原数组

  4. 重复直到所有字母处理完毕

C语言代码

复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_WORDS 100
#define WORD_LEN 10
#define ALPHABET 26

void radixSortWords(char words[][WORD_LEN + 1], int n, int len) {
    char buckets[ALPHABET][MAX_WORDS][WORD_LEN + 1];
    int bucketSize[ALPHABET] = {0};
    
    for (int pos = len - 1; pos >= 0; pos--) {
        // 分配
        for (int i = 0; i < n; i++) {
            int idx = words[i][pos] - 'a';
            strcpy(buckets[idx][bucketSize[idx]++], words[i]);
        }
        // 收集
        int idx = 0;
        for (int i = 0; i < ALPHABET; i++) {
            for (int j = 0; j < bucketSize[i]; j++) {
                strcpy(words[idx++], buckets[i][j]);
            }
            bucketSize[i] = 0;
        }
    }
}

C++代码

复制代码
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;

void radixSortWords(vector<string>& words, int len) {
    for (int pos = len - 1; pos >= 0; pos--) {
        vector<vector<string>> buckets(26);
        for (const string& w : words) {
            buckets[w[pos] - 'a'].push_back(w);
        }
        words.clear();
        for (auto& bucket : buckets) {
            words.insert(words.end(), bucket.begin(), bucket.end());
        }
    }
}

(4) 编写算法,以顺序队列实现基数排序。

核心思路

  1. 使用队列数组作为桶

  2. 入队操作替代分配到桶

  3. 出队操作替代收集

C语言代码

复制代码
#include <stdio.h>
#include <stdlib.h>

#define MAX 100
#define RADIX 10

typedef struct {
    int data[MAX];
    int front, rear;
} Queue;

void initQueue(Queue* q) {
    q->front = q->rear = 0;
}

int isEmpty(Queue* q) {
    return q->front == q->rear;
}

void enqueue(Queue* q, int val) {
    q->data[q->rear++] = val;
}

int dequeue(Queue* q) {
    return q->data[q->front++];
}

void radixSortQueue(int arr[], int n, int maxDigits) {
    Queue buckets[RADIX];
    for (int i = 0; i < RADIX; i++) initQueue(&buckets[i]);
    
    int exp = 1;
    for (int d = 0; d < maxDigits; d++) {
        // 分配
        for (int i = 0; i < n; i++) {
            int digit = (arr[i] / exp) % 10;
            enqueue(&buckets[digit], arr[i]);
        }
        // 收集
        int idx = 0;
        for (int i = 0; i < RADIX; i++) {
            while (!isEmpty(&buckets[i])) {
                arr[idx++] = dequeue(&buckets[i]);
            }
        }
        exp *= 10;
    }
}

C++代码

复制代码
#include <iostream>
#include <queue>
#include <vector>
using namespace std;

void radixSortQueue(vector<int>& arr, int maxDigits) {
    int exp = 1;
    for (int d = 0; d < maxDigits; d++) {
        vector<queue<int>> buckets(10);
        for (int num : arr) {
            int digit = (num / exp) % 10;
            buckets[digit].push(num);
        }
        arr.clear();
        for (auto& bucket : buckets) {
            while (!bucket.empty()) {
                arr.push_back(bucket.front());
                bucket.pop();
            }
        }
        exp *= 10;
    }
}

(5) 计数排序(Counting Sort)

核心思路

  1. 对每个元素,统计有多少个元素比它小

  2. 该统计值就是它在结果数组中的位置

C语言代码

复制代码
#include <stdlib.h>

void countingSort(int A[], int B[], int n) {
    for (int i = 0; i < n; i++) {
        int count = 0;
        for (int j = 0; j < n; j++) {
            if (A[j] < A[i]) count++;
        }
        B[count] = A[i];
    }
}

C++代码

复制代码
#include <vector>
using namespace std;

vector<int> countingSort(const vector<int>& A) {
    int n = A.size();
    vector<int> B(n);
    for (int i = 0; i < n; i++) {
        int count = 0;
        for (int j = 0; j < n; j++) {
            if (A[j] < A[i]) count++;
        }
        B[count] = A[i];
    }
    return B;
}

(6) 表插入排序(静态链表实现)

核心思路

  1. 使用静态链表结构(数组 + next指针)

  2. 插入时只修改next指针,不移动元素

  3. 最后按next顺序输出

C语言代码

复制代码
#include <stdio.h>

#define MAX 100

typedef struct {
    int data;
    int next;
} StaticLink;

void tableInsertSort(StaticLink list[], int n) {
    // 初始化头结点
    list[0].next = 1;
    list[1].next = -1;
    
    for (int i = 2; i <= n; i++) {
        int p = 0;
        int q = list[p].next;
        while (q != -1 && list[q].data < list[i].data) {
            p = q;
            q = list[q].next;
        }
        list[p].next = i;
        list[i].next = q;
    }
}

C++代码

复制代码
#include <iostream>
#include <vector>
using namespace std;

struct StaticLink {
    int data;
    int next;
};

void tableInsertSort(vector<StaticLink>& list) {
    int n = list.size() - 1;
    list[0].next = 1;
    list[1].next = -1;
    
    for (int i = 2; i <= n; i++) {
        int p = 0;
        int q = list[p].next;
        while (q != -1 && list[q].data < list[i].data) {
            p = q;
            q = list[q].next;
        }
        list[p].next = i;
        list[i].next = q;
    }
}

(7) 数组循环右移k位(O(n)时间,O(1)空间)

核心思路

三步反转法:

  1. 反转整个数组

  2. 反转前k个元素

  3. 反转后n-k个元素

C语言代码

复制代码
void reverse(int A[], int l, int r) {
    while (l < r) {
        int temp = A[l];
        A[l] = A[r];
        A[r] = temp;
        l++; r--;
    }
}

void rightRotate(int A[], int n, int k) {
    if (n == 0) return;
    k = k % n;
    if (k == 0) return;
    reverse(A, 0, n - 1);
    reverse(A, 0, k - 1);
    reverse(A, k, n - 1);
}

C++代码

复制代码
#include <algorithm>
#include <vector>
using namespace std;

void rightRotate(vector<int>& A, int k) {
    int n = A.size();
    if (n == 0) return;
    k %= n;
    if (k == 0) return;
    reverse(A.begin(), A.end());
    reverse(A.begin(), A.begin() + k);
    reverse(A.begin() + k, A.end());
}

(8) 鸡尾酒排序(双向冒泡排序)

核心思路

  1. 每趟交替方向

  2. 奇数趟从左到右冒泡(最大沉底)

  3. 偶数趟从右到左冒泡(最小上浮)

C语言代码

复制代码
void cocktailSort(int A[], int n) {
    int left = 0, right = n - 1;
    int swapped = 1;
    
    while (left < right && swapped) {
        swapped = 0;
        // 从左到右
        for (int i = left; i < right; i++) {
            if (A[i] > A[i + 1]) {
                int temp = A[i];
                A[i] = A[i + 1];
                A[i + 1] = temp;
                swapped = 1;
            }
        }
        right--;
        if (!swapped) break;
        // 从右到左
        for (int i = right; i > left; i--) {
            if (A[i] < A[i - 1]) {
                int temp = A[i];
                A[i] = A[i - 1];
                A[i - 1] = temp;
                swapped = 1;
            }
        }
        left++;
    }
}

C++代码

复制代码
void cocktailSort(vector<int>& A) {
    int left = 0, right = A.size() - 1;
    bool swapped = true;
    
    while (left < right && swapped) {
        swapped = false;
        for (int i = left; i < right; i++) {
            if (A[i] > A[i + 1]) {
                swap(A[i], A[i + 1]);
                swapped = true;
            }
        }
        right--;
        if (!swapped) break;
        for (int i = right; i > left; i--) {
            if (A[i] < A[i - 1]) {
                swap(A[i], A[i - 1]);
                swapped = true;
            }
        }
        left++;
    }
}

(9) 荷兰国旗问题(红、白、蓝三色排序)

核心思路

三指针法:

  • red 指向红色区域的末尾

  • white 当前扫描指针

  • blue 指向蓝色区域的开头

C语言代码

复制代码
typedef enum { RED, WHITE, BLUE } Color;

void dutchFlag(Color arr[], int n) {
    int red = 0, white = 0, blue = n - 1;
    
    while (white <= blue) {
        switch (arr[white]) {
            case RED:
                Color temp = arr[red];
                arr[red] = arr[white];
                arr[white] = temp;
                red++;
                white++;
                break;
            case WHITE:
                white++;
                break;
            case BLUE:
                temp = arr[white];
                arr[white] = arr[blue];
                arr[blue] = temp;
                blue--;
                break;
        }
    }
}

C++代码

复制代码
#include <vector>
using namespace std;

enum Color { RED, WHITE, BLUE };

void dutchFlag(vector<Color>& arr) {
    int red = 0, white = 0, blue = arr.size() - 1;
    
    while (white <= blue) {
        switch (arr[white]) {
            case RED:
                swap(arr[red], arr[white]);
                red++;
                white++;
                break;
            case WHITE:
                white++;
                break;
            case BLUE:
                swap(arr[white], arr[blue]);
                blue--;
                break;
        }
    }
}

(10) 求两个有序数组的中位数(O(log n))

核心思路

  1. 在较短的数组上二分查找切分点

  2. 保证左半部分长度 = (n+m+1)/2

  3. 调整切分位置使左半部分最大值 ≤ 右半部分最小值

C语言代码

复制代码
#include <limits.h>

double findMedianSortedArrays(int A[], int m, int B[], int n) {
    if (m > n) return findMedianSortedArrays(B, n, A, m);
    
    int left = 0, right = m;
    while (left <= right) {
        int i = (left + right) / 2;
        int j = (m + n + 1) / 2 - i;
        
        int maxLeftA = (i == 0) ? INT_MIN : A[i - 1];
        int minRightA = (i == m) ? INT_MAX : A[i];
        int maxLeftB = (j == 0) ? INT_MIN : B[j - 1];
        int minRightB = (j == n) ? INT_MAX : B[j];
        
        if (maxLeftA <= minRightB && maxLeftB <= minRightA) {
            if ((m + n) % 2 == 0) {
                return (double)(max(maxLeftA, maxLeftB) + min(minRightA, minRightB)) / 2;
            } else {
                return (double)max(maxLeftA, maxLeftB);
            }
        } else if (maxLeftA > minRightB) {
            right = i - 1;
        } else {
            left = i + 1;
        }
    }
    return 0.0;
}

C++代码

复制代码
#include <vector>
#include <algorithm>
#include <climits>
using namespace std;

double findMedianSortedArrays(const vector<int>& A, const vector<int>& B) {
    int m = A.size(), n = B.size();
    if (m > n) return findMedianSortedArrays(B, A);
    
    int left = 0, right = m;
    while (left <= right) {
        int i = (left + right) / 2;
        int j = (m + n + 1) / 2 - i;
        
        int maxLeftA = (i == 0) ? INT_MIN : A[i - 1];
        int minRightA = (i == m) ? INT_MAX : A[i];
        int maxLeftB = (j == 0) ? INT_MIN : B[j - 1];
        int minRightB = (j == n) ? INT_MAX : B[j];
        
        if (maxLeftA <= minRightB && maxLeftB <= minRightA) {
            if ((m + n) % 2 == 0) {
                return (max(maxLeftA, maxLeftB) + min(minRightA, minRightB)) / 2.0;
            } else {
                return max(maxLeftA, maxLeftB);
            }
        } else if (maxLeftA > minRightB) {
            right = i - 1;
        } else {
            left = i + 1;
        }
    }
    return 0.0;
}

注:以上习题解答的理解和计算,如果有任何错误,希望各位读者和大佬指出改正,非常感谢!!!

相关推荐
高锰酸钾_1 小时前
计算机网络-链路层-局域网与IEEE
网络·计算机网络
Sherlock Ma10 小时前
西瓜书《机器学习》全网最详细解读 第一章:绪论
人工智能·深度学习·考研·机器学习·学习方法·西瓜书·改行学it
高锰酸钾_11 小时前
计算机网络-链路层-介质访问控制
网络·计算机网络
Java成神之路-15 小时前
深入理解网络通信基石:网口、MAC 地址与 IP 地址如何分工协作
tcp/ip·计算机网络
高锰酸钾_16 小时前
计算机网络-链路层-差错控制
服务器·网络·计算机网络
Java成神之路-19 小时前
ARP、RARP与代理ARP详解
tcp/ip·计算机网络
夏乌_Wx20 小时前
计算机网络实践项目 | 云相册(文件互传与管理系统)
linux·计算机网络
博界IT精灵20 小时前
二叉排序树和平衡二叉树(哈喜老师)
数据结构·考研
Chockmans21 小时前
春秋云境CVE-2022-32991(手注和sqlmap)保姆级教学
数据库·安全·web安全·网络安全·oracle·春秋云境·cve-2022-32991