笔试面试01 c/c++

发布于:2025-03-26 ⋅ 阅读:(31) ⋅ 点赞:(0)

基础知识

  1. 什么是数据结构?请简要描述常见的数据结构类型。
    数据结构是组织和存储数据的方式,以便于高效访问和修改。常见的数据结构包括:
    数组:固定大小的线性数据结构,支持随机访问。
    链表:由节点组成的线性数据结构,每个节点包含数据和指向下一个节点的指针。
    :后进先出(LIFO)的数据结构,支持 push 和 pop 操作。
    队列:先进先出(FIFO)的数据结构,支持入队和出队操作。
    哈希表:通过哈希函数将键映射到值的集合,支持快速查找。
    :层次结构的数据结构,常见的有二叉树、二叉搜索树等。
    :由节点和边组成的非线性数据结构,用于表示关系。

  2. 解释时间复杂度和空间复杂度的概念。如何评估算法的效率?
    时间复杂度:表示算法执行所需时间的增长率,通常用大 O 表示法表示(如 O(n)、O(log n))。
    空间复杂度:表示算法所需空间的增长率,也用大 O 表示法表示。
    评估算法的效率通常通过分析其时间复杂度和空间复杂度,比较不同算法在处理相同问题时的性能。

  3. 什么是递归?请给出一个递归的例子。
    递归是指函数直接或间接调用自身的编程技术。递归通常由基本情况和递归情况组成。

例子:计算阶乘的递归函数

int factorial(int n) {
    if (n == 0) {
        return 1; // 基本情况
    }
    return n * factorial(n - 1); // 递归情况
}
  1. 描述栈和队列的区别,并给出它们的应用场景。
    栈:
    后进先出(LIFO)结构。
    应用场景:函数调用管理、表达式求值、撤销操作。
    队列:
    先进先出(FIFO)结构。
    应用场景:任务调度、消息队列、打印任务管理。

编程题

编写一个函数,反转一个链表。

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

struct ListNode* reverseList(struct ListNode* head) {
    struct ListNode *prev = NULL, *current = head, *next = NULL;
    while (current != NULL) {
        next = current->next; // 保存下一个节点
        current->next = prev; // 反转指针
        prev = current;       // 移动 prev 和 current
        current = next;
    }
    return prev; // 新的头节点
}

编写一个 C 程序,判断一个字符串是否是回文。

int isPalindrome(char *s) {
    int left = 0, right = strlen(s) - 1;
    while (left < right) {
        if (s[left] != s[right]) {
            return 0; // 不是回文
        }
        left++;
        right--;
    }
    return 1; // 是回文
}

给定一个数组,编写一个函数,找出数组中的最大值和最小值。

void findMaxMin(int arr[], int size, int *max, int *min) {
    *max = arr[0];
    *min = arr[0];
    for (int i = 1; i < size; i++) {
        if (arr[i] > *max) {
            *max = arr[i];
        }
        if (arr[i] < *min) {
            *min = arr[i];
        }
    }
}

算法题

实现快速排序算法。

void quickSort(int arr[], int low, int high) {
    if (low < high) {
        int pivot = partition(arr, low, high);
        quickSort(arr, low, pivot - 1);
        quickSort(arr, pivot + 1, high);
    }
}

int partition(int arr[], int low, int high) {
    int pivot = arr[high];
    int i = (low - 1);
    for (int j = low; j < high; j++) {
        if (arr[j] < pivot) {
            i++;
            swap(&arr[i], &arr[j]);
        }
    }
    swap(&arr[i + 1], &arr[high]);
    return (i + 1);
}

void swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

实现二分搜索算法。

int binarySearch(int arr[], int size, int target) {
    int left = 0, right = size - 1;
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (arr[mid] == target) {
            return mid; // 找到目标
        }
        if (arr[mid] < target) {
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }
    return -1; // 未找到目标
}

编写一个函数,找出斐波那契数列的第 n 项。

unsigned long long fibonacci(int n) {
    if (n <= 1) {
        return n;
    }
    return fibonacci(n - 1) + fibonacci(n - 2);
}

进阶题

给定一个无序数组,编写一个函数找出其中的第 k 大元素。

#include <stdio.h>
#include <stdlib.h>

// 交换两个整数
void swap(int *a, int *b) {
   int temp = *a;
   *a = *b;
   *b = temp;
}

// 分区函数
int partition(int arr[], int left, int right, int pivotIndex) {
   int pivotValue = arr[pivotIndex];
   swap(&arr[pivotIndex], &arr[right]); // 将 pivot 移到末尾
   int storeIndex = left;

   for (int i = left; i < right; i++) {
       if (arr[i] > pivotValue) { // 找第 k 大元素,使用大于
           swap(&arr[storeIndex], &arr[i]);
           storeIndex++;
       }
   }
   swap(&arr[storeIndex], &arr[right]); // 将 pivot 移回
   return storeIndex;
}

// 快速选择函数
int quickSelect(int arr[], int left, int right, int k) {
   if (left == right) {
       return arr[left]; // 只有一个元素
   }

   int pivotIndex = left + rand() % (right - left + 1); // 随机选择 pivot
   pivotIndex = partition(arr, left, right, pivotIndex);

   // 计算 pivot 的位置
   if (k == pivotIndex) {
       return arr[k]; // 找到第 k 大元素
   } else if (k < pivotIndex) {
       return quickSelect(arr, left, pivotIndex - 1, k); // 在左侧
   } else {
       return quickSelect(arr, pivotIndex + 1, right, k); // 在右侧
   }
}

// 主函数
int findKthLargest(int* nums, int numsSize, int k) {
   // k 是第 k 大元素,转换为索引
   return quickSelect(nums, 0, numsSize - 1, k - 1);
}

// 测试
int main() {
   int arr[] = {3, 2, 1, 5, 6, 4};
   int k = 2; // 找出第 2 大元素
   int size = sizeof(arr) / sizeof(arr[0]);
   int result = findKthLargest(arr, size, k);
   printf("The %dth largest element is %d\n", k, result);
   return 0;
}

实现一个简单的哈希表。

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

#define TABLE_SIZE 10 // 哈希表大小

// 哈希表节点
typedef struct Node {
   int key;
   int value;
   struct Node* next; // 链表中的下一个节点
} Node;

// 哈希表结构
typedef struct HashTable {
   Node** table; // 指向节点指针的数组
} HashTable;

// 哈希函数
int hash(int key) {
   return key % TABLE_SIZE;
}

// 创建哈希表
HashTable* createHashTable() {
   HashTable* ht = malloc(sizeof(HashTable));
   ht->table = malloc(sizeof(Node*) * TABLE_SIZE);
   for (int i = 0; i < TABLE_SIZE; i++) {
       ht->table[i] = NULL; // 初始化为 NULL
   }
   return ht;
}

// 插入键值对
void insert(HashTable* ht, int key, int value) {
   int index = hash(key);
   Node* newNode = malloc(sizeof(Node));
   newNode->key = key;
   newNode->value = value;
   newNode->next = ht->table[index]; // 插入到链表头部
   ht->table[index] = newNode;
}

// 查找值
int search(HashTable* ht, int key) {
   int index = hash(key);
   Node* current = ht->table[index];
   while (current != NULL) {
       if (current->key == key) {
           return current->value; // 找到值
       }
       current = current->next;
   }
   return -1; // 未找到
}

// 删除键值对
void delete(HashTable* ht, int key) {
   int index = hash(key);
   Node* current = ht->table[index];
   Node* prev = NULL;

   while (current != NULL) {
       if (current->key == key) {
           if (prev == NULL) {
               ht->table[index] = current->next; // 删除头节点
           } else {
               prev->next = current->next; // 删除中间或尾节点
           }
           free(current);
           return;
       }
       prev = current;
       current = current->next;
   }
}

// 释放哈希表
void freeHashTable(HashTable* ht) {
   for (int i = 0; i < TABLE_SIZE; i++) {
       Node* current = ht->table[i];
       while (current != NULL) {
           Node* temp = current;
           current = current->next;
           free(temp);
       }
   }
   free(ht->table);
   free(ht);
}

// 测试
int main() {
   HashTable* ht = createHashTable();
   insert(ht, 1, 100);
   insert(ht, 2, 200);
   insert(ht, 12, 300); // 12 会与 2 哈希到同一位置

   printf("Value for key 1: %d\n", search(ht, 1)); // 输出 100
   printf("Value for key 2: %d\n", search(ht, 2)); // 输出 200
   printf("Value for key 12: %d\n", search(ht, 12)); // 输出 300

   delete(ht, 2);
   printf("Value for key 2 after deletion: %d\n", search(ht, 2)); // 输出 -1

   freeHashTable(ht);
   return 0;
}

设计与应用

设计一个简单的任务调度系统,描述其数据结构和算法。

  1. 数据结构:使用队列来管理任务,使用结构体存储任务信息(如任务 ID、优先级、状态等)。
    任务结构体(Task):
    用于表示一个任务的基本信息。
typedef struct Task {
   int id;                // 任务 ID
   char name[50];        // 任务名称
   int priority;         // 任务优先级
   int burst_time;       // 任务所需的 CPU 时间
   struct Task* next;    // 指向下一个任务的指针
} Task;

任务队列(TaskQueue):
用于存储待调度的任务。

typedef struct TaskQueue {
   Task* front;          // 队列前端
   Task* rear;           // 队列后端
} TaskQueue;

  1. 算法: 实现任务的添加、删除和调度算法(如优先级调度)。
    任务添加:
    将新任务添加到任务队列中,按照优先级排序(高优先级在前)。
void enqueue(TaskQueue* queue, Task* newTask) {
   if (queue->front == NULL) {
       queue->front = newTask;
       queue->rear = newTask;
       newTask->next = NULL;
   } else {
       Task* current = queue->front;
       Task* previous = NULL;

       // 找到插入位置
       while (current != NULL && current->priority >= newTask->priority) {
           previous = current;
           current = current->next;
       }

       if (previous == NULL) {
           // 插入到队列前端
           newTask->next = queue->front;
           queue->front = newTask;
       } else {
           // 插入到中间或后端
           newTask->next = current;
           previous->next = newTask;
       }

       if (current == NULL) {
           // 更新队列后端
           queue->rear = newTask;
       }
   }
}

任务调度:
从队列中取出优先级最高的任务并执行。

Task* dequeue(TaskQueue* queue) {
   if (queue->front == NULL) {
       return NULL; // 队列为空
   }

   Task* taskToExecute = queue->front;
   queue->front = queue->front->next;

   if (queue->front == NULL) {
       queue->rear = NULL; // 队列变为空
   }

   return taskToExecute;
}

任务执行:
模拟任务的执行过程,输出任务信息。

void executeTask(Task* task) {
   printf("Executing Task ID: %d, Name: %s, Priority: %d, Burst Time: %d\n",
          task->id, task->name, task->priority, task->burst_time);
   // 这里可以添加实际的执行逻辑
}

  1. 主函数示例
int main() {
   TaskQueue queue = {NULL, NULL}; // 初始化任务队列

   // 创建一些任务
   Task task1 = {1, "Task 1", 2, 5, NULL};
   Task task2 = {2, "Task 2", 1, 3, NULL};
   Task task3 = {3, "Task 3", 3, 2, NULL};

   // 添加任务到队列
   enqueue(&queue, &task1);
   enqueue(&queue, &task2);
   enqueue(&queue, &task3);

   // 执行任务
   Task* task;
   while ((task = dequeue(&queue)) != NULL) {
       executeTask(task);
   }

   return 0;
}

给定一个图,编写一个函数实现深度优先搜索(DFS)和广度优先搜索(BFS)。

#include <stdio.h>
#include <stdlib.h>

#define MAX 100 // 最大节点数

// 图的邻接表节点
typedef struct Node {
   int vertex;
   struct Node* next;
} Node;

// 图的结构
typedef struct Graph {
   Node* adjList[MAX];
   int visited[MAX];
   int numVertices;
} Graph;

// 创建图
Graph* createGraph(int vertices) {
   Graph* graph = malloc(sizeof(Graph));
   graph->numVertices = vertices;

   for (int i = 0; i < vertices; i++) {
       graph->adjList[i] = NULL;
       graph->visited[i] = 0; // 初始化访问状态
   }
   return graph;
}

// 添加边
void addEdge(Graph* graph, int src, int dest) {
   Node* newNode = malloc(sizeof(Node));
   newNode->vertex = dest;
   newNode->next = graph->adjList[src];
   graph->adjList[src] = newNode;

   // 如果是无向图,添加反向边
   newNode = malloc(sizeof(Node));
   newNode->vertex = src;
   newNode->next = graph->adjList[dest];
   graph->adjList[dest] = newNode;
}

// 深度优先搜索(DFS)
void DFS(Graph* graph, int vertex) {
   graph->visited[vertex] = 1; // 标记为已访问
   printf("%d ", vertex); // 处理节点

   Node* temp = graph->adjList[vertex];
   while (temp) {
       int connectedVertex = temp->vertex;
       if (!graph->visited[connectedVertex]) {
           DFS(graph, connectedVertex);
       }
       temp = temp->next;
   }
}

// 广度优先搜索(BFS)
void BFS(Graph* graph, int startVertex) {
   int queue[MAX], front = 0, rear = 0;
   graph->visited[startVertex] = 1; // 标记为已访问
   queue[rear++] = startVertex; // 入队

   while (front < rear) {
       int currentVertex = queue[front++]; // 出队
       printf("%d ", currentVertex); // 处理节点

       Node* temp = graph->adjList[currentVertex];
       while (temp) {
           int connectedVertex = temp->vertex;
           if (!graph->visited[connectedVertex]) {
               graph->visited[connectedVertex] = 1; // 标记为已访问
               queue[rear++] = connectedVertex; // 入队
           }
           temp = temp->next;
       }
   }
}

// 主函数
int main() {
   Graph* graph = createGraph(5); // 创建一个包含 5 个节点的图
   addEdge(graph, 0, 1);
   addEdge(graph, 0, 4);
   addEdge(graph, 1, 2);
   addEdge(graph, 1, 3);
   addEdge(graph, 1, 4);
   addEdge(graph, 2, 3);
   addEdge(graph, 3, 4);

   printf("DFS traversal starting from vertex 0:\n");
   DFS(graph, 0);
   printf("\n");

   // 重置访问状态
   for (int i = 0; i < graph->numVertices; i++) {
       graph->visited[i] = 0;
   }

   printf("BFS traversal starting from vertex 0:\n");
   BFS(graph, 0);
   printf("\n");

   return 0;
}