摘要:本文将详细介绍C语言数据结构算法面试笔试题的相关知识点,包括链表、数组、二叉树等常见数据结构的经典算法题目。我们将分析每个题目的解题思路、C语言实现及时间和空间复杂度,帮助读者在面试笔试中脱颖而出。
正文:
一、引言
数据结构算法是计算机科学与技术领域的基础知识,对于求职者来说,掌握数据结构算法是必备技能。在面试笔试中,数据结构算法题目占据了很大的比重。本文将针对C语言数据结构算法面试笔试题进行详细解析,帮助读者应对各种笔试题目。
二、链表相关题目
1. 链表中特定值节点的删除
题目:给定一个链表,删除链表中所有值为x的节点。
解题思路:遍历链表,使用while循环和if条件语句判断节点值,删除符合条件的节点。
C语言实现:
“`c
void deleteNode(ListNode* head, int x) {
ListNode* current = head;
ListNode* prev = NULL;
while (current != NULL) {
if (current->val == x) {
if (prev == NULL) {
head = current->next;
} else {
prev->next = current->next;
}
free(current);
current = prev->next;
} else {
prev = current;
current = current->next;
}
}
}
“`
时间复杂度:O(n),空间复杂度:O(1)
2. �链表最小值节点的删除
题目:给定一个链表,删除链表中的最小值节点。
解题思路:遍历链表,记录最小值节点的前驱和最小值节点,最后删除最小值节点。
C语言实现:
“`c
void deleteMinNode(ListNode* head) {
ListNode* current = head;
ListNode* prevMin = NULL;
ListNode* minNode = NULL;
while (current != NULL) {
if (minNode == NULL || current->val val) {
minNode = current;
prevMin = prev;
}
current = current->next;
}
if (prevMin == NULL) {
head = minNode->next;
} else {
prevMin->next = minNode->next;
}
free(minNode);
}
“`
时间复杂度:O(n),空间复杂度:O(1)
(注:以下题目类似,仅提供题目、解题思路和C语言实现,不再重复时间和空间复杂度分析)
3. 链表的头插法
题目:实现链表的头插法。
解题思路:创建新节点,插入到链表头部。
C语言实现:
“`c
void insertAtHead(ListNode** head, int x) {
ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));
newNode->val = x;
newNode->next = *head;
*head = newNode;
}
“`
4. 链表的尾插法
题目:实现链表的尾插法。
解题思路:创建新节点,插入到链表尾部。
C语言实现:
“`c
void insertAtTail(ListNode** head, int x) {
ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));
newNode->val = x;
newNode->next = NULL;
if (*head == NULL) {
*head = newNode;
} else {
ListNode* current = *head;
while (current->next != NULL) {
current = current->next;
}
current->next = newNode;
}
}
“`
5. 链表的逆置
题目:给定一个链表,实现链表的逆置。
解题思路:使用三个指针分别记录当前节点、前一个节点和后一个节点,实现链表的逆置。
C语言实现:
“`c
void reverseList(ListNode** head) {
ListNode* prev = NULL;
ListNode* current = *head;
ListNode* next = NULL;
while (current != NULL) {
next = current->next;
current->next = prev;
prev = current;
current = next;
}
*head = prev;
}
“`
6. 链表中特定区间元素的删除
题目:给定一个链表,删除链表中位于区间内的所有元素。
解题思路:遍历链表,删除区间内的节点。
C语言实现:
“`c
void deleteRange(ListNode** head, int a, int b) {
ListNode* current = *head;
ListNode* prev = NULL;
while (current != NULL) {
if (current->val >= a && current->val <= b) {
if (prev == NULL) {
*head = current->next;
} else {
prev->next = current->next;
}
free(current);
current = prev->next;
} else {
prev = current;
current = current->next;
}
}
}
“`
7. 找出两个链表的公共节点
题目:给定两个链表,找出它们的公共节点。
解题思路:使用哈希表记录第一个链表的节点,遍历第二个链表,查找公共节点。
C语言实现:
“`c
ListNode* findCommonNode(ListNode* head1, ListNode* head2) {
HashSet set;
while (head1 != NULL) {
set.add(head1);
head1 = head1->next;
}
while (head2 != NULL) {
if (set.contains(head2)) {
return head2;
}
head2 = head2->next;
}
return NULL;
}
“`
8. 链表奇偶位序元素的分离
题目:给定一个链表,将奇数位序的元素和偶数位序的元素分离。
解题思路:分别使用两个链表存储奇数位序和偶数位序的元素,最后合并两个链表。
C语言实现:
“`c
void separateOddEven(ListNode** head) {
ListNode* oddHead = NULL;
ListNode* evenHead = NULL;
ListNode* oddTail = NULL;
ListNode* evenTail = NULL;
int index = 1;
while (*head != NULL) {
if (index % 2 == 1) {
if (oddTail == NULL) {
oddHead = oddTail = *head;
} else {
oddTail->next = *head;
oddTail = oddTail->next;
}
} else {
if (evenTail == NULL) {
evenHead = evenTail = *head;
} else {
evenTail->next = *head;
evenTail = evenTail->next;
}
}
*head = (*head)->next;
index++;
}
if (oddTail != NULL) {
oddTail->next = evenHead;
}
*head = oddHead;
}
“`
9. 链表奇偶位序元素的分离,一个头插一个尾插
题目:给定一个链表,将奇数位序的元素和偶数位序的元素分离,奇数位序元素使用头插法,偶数位序元素使用尾插法。
解题思路:分别使用头插法和尾插法处理奇数位序和偶数位序的元素。
C语言实现:
“`c
void separateOddEvenWithInsert(ListNode** head) {
ListNode* oddHead = NULL;
ListNode* evenHead = NULL;
ListNode* oddTail = NULL;
ListNode* evenTail = NULL;
int index = 1;
while (*head != NULL) {
if (index % 2 == 1) {
insertAtHead(&oddHead, (*head)->val);
} else {
insertAtTail(&evenHead, (*head)->val);
}
*head = (*head)->next;
index++;
}
oddTail = oddHead;
while (oddTail != NULL && oddTail->next != NULL) {
oddTail = oddTail->next;
}
if (oddTail != NULL) {
oddTail->next = evenHead;
}
*head = oddHead;
}
“`
10. 链表的去重
题目:给定一个链表,删除链表中重复的节点。
解题思路:使用哈希表记录已遍历的节点,删除重复节点。
C语言实现:
“`c
void deleteDuplicates(ListNode** head) {
HashSet set;
ListNode* current = *head;
ListNode* prev = NULL;
while (current != NULL) {
if (set.contains(current->val)) {
prev->next = current->next;
free(current);
current = prev->next;
} else {
set.add(current->val);
prev = current;
current = current->next;
}
}
}
“`
三、数组相关题目
1. 数组元素的倒置
题目:给定一个数组,实现数组元素的倒置。
解题思路:使用双指针法,一个指针指向数组头部,另一个指针指向数组尾部,交换两个指针指向的元素,然后移动指针,直到两个指针相遇。
C语言实现:
“`c
void reverseArray(int* arr, int size) {
int left = 0;
int right = size – 1;
while (left < right) {
int temp = arr;
arr = arr;
arr = temp;
left++;
right–;
}
}
“`
2. 数组中特定值元素的删除
题目:给定一个数组,删除数组中所有值为x的元素。
解题思路:使用双指针法,一个指针用于遍历数组,另一个指针用于指向下一个插入位置。遍历数组时,如果当前元素不等于x,则将其复制到下一个插入位置。
C语言实现:
“`c
int removeElement(int* arr, int size, int x) {
int i = 0;
for (int j = 0; j < size; j++) {
if (arr != x) {
arr = arr;
}
}
return i;
}
“`
3. 数组中值位于某一区间的元素的删除
题目:给定一个数组,删除数组中值位于区间内的所有元素。
解题思路:使用双指针法,一个指针用于遍历数组,另一个指针用于指向下一个插入位置。遍历数组时,如果当前元素不在区间内,则将其复制到下一个插入位置。
C语言实现:
“`c
int removeRange(int* arr, int size, int a, int b) {
int i = 0;
for (int j = 0; j < size; j++) {
if (arr b) {
arr = arr;
}
}
return i;
}
“`
4. 数组的去重
题目:给定一个数组,删除数组中的重复元素。
解题思路:首先对数组进行排序,然后使用双指针法删除重复元素。
C语言实现:
“`c
int removeDuplicates(int* arr, int size) {
if (size == 0) return 0;
qsort(arr, size, sizeof(int), compare);
int i = 0;
for (int j = 1; j < size; j++) {
if (arr != arr) {
i++;
arr = arr;
}
}
return i + 1;
}
“`
5. 数组中两个子数组的位置互换
题目:给定一个数组,将数组中前k个元素和后k个元素的位置互换。
解题思路:使用双指针法,一个指针指向前k个元素的尾部,另一个指针指向后k个元素的开头,交换两个指针指向的元素,然后移动指针,直到完成k次交换。
C语言实现:
“`c
void swapSubarrays(int* arr, int size, int k) {
int left = k – 1;
int right = size – k;
while (left >= 0 && right < size) {
int temp = arr;
arr = arr;
arr = temp;
left–;
right++;
}
}
“`
6. 数组元素的循环移动
题目:给定一个数组,将数组中的元素循环移动k个位置。
解题思路:先将数组分为两部分,然后将这两部分逆置,最后将整个数组逆置。
C语言实现:
“`c
void rotateArray(int* arr, int size, int k) {
k %= size;
reverseArray(arr, k);
reverseArray(arr + k, size – k);
reverseArray(arr, size);
}
“`
四、二叉树相关题目
1. 根据后序遍历和中序遍历序列构造二叉树
题目:给定一棵二叉树的后序遍历序列和中序遍历序列,构造该二叉树。
解题思路:后序遍历的最后一个元素为根节点,在中序遍历中找到根节点的位置,将中序遍历序列分为左子树和右子树两部分,递归构造左右子树。
C语言实现:
“`c
TreeNode* buildTree(vector& inorder, vector& postorder) {
if (inorder.empty() || postorder.empty()) return NULL;
int rootVal = postorder.back();
TreeNode* root = new TreeNode(rootVal);
int rootIndex = find(inorder.begin(), inorder.end(), rootVal) – inorder.begin();
vector leftInorder(inorder.begin(), inorder.begin() + rootIndex);
vector rightInorder(inorder.begin() + rootIndex + 1, inorder.end());
vector leftPostorder(postorder.begin(), postorder.begin() + rootIndex);
vector rightPostorder(postorder.begin() + rootIndex, postorder.end() – 1);
root->left = buildTree(leftInorder, leftPostorder);
root->right = buildTree(rightInorder, rightPostorder);
return root;
}
“`
2. 求二叉树第k层的节点个数
题目:给定一棵二叉树,求第k层的节点个数。
解题思路:使用递归方法,逐层向下计算到达指定层时返回1,从而累加得到该层的节点数。
C语言实现:
“`c
int getNodesAtKthLevel(TreeNode* root, int k) {
if (root == NULL || k <= 0) return 0;
if (k == 1) return 1;
return getNodesAtKthLevel(root->left, k – 1) + getNodesAtKthLevel(root->right, k – 1);
}
“`
3. 查找一个节点是否在二叉树中
题目:给定一棵二叉树和一个节点值x,查找x是否在二叉树中。
解题思路:使用递归遍历二叉树,若找到匹配节点则返回该节点指针,否则返回null。
C语言实现:
“`c
TreeNode* searchNode(TreeNode* root, int x) {
if (root == NULL) return NULL;
if (root->val == x) return root;
TreeNode* left = searchNode(root->left, x);
if (left != NULL) return left;
return searchNode(root->right, x);
}
“`
4. 求二叉树的节点个数
题目:给定一棵二叉树,求二叉树的节点个数。
解题思路:可以通过遍历方法或分治方法来进行计算,遍历方法通过递归计数,分治方法则是每个节点返回1,累加得到总数。
C语言实现:
“`c
int countNodes(TreeNode* root) {
if (root == NULL) return 0;
return 1 + countNodes(root->left) + countNodes(root->right);
}
“`
5. 求二叉树叶子节点的个数
题目:给定一棵二叉树,求二叉树叶子节点的个数。
解题思路:通过递归判断节点是否为叶子节点(无子节点),若是则计数1,累加所有叶子节点的计数得到总数。
C语言实现:
“`c
int countLeafNodes(TreeNode* root) {
if (root == NULL) return 0;
if (root->left == NULL && root->right == NULL) return 1;
return countLeafNodes(root->left) + countLeafNodes(root->right);
}
“`
6. 求树的深度
题目:给定一棵二叉树,求树的深度。
解题思路:通过递归比较左右子树的深度,返回最大深度加1来得到树的深度。
C语言实现:
“`c
int getDepth(TreeNode* root) {
if (root == NULL) return 0;
int leftDepth = getDepth(root->left);
int rightDepth = getDepth(root->right);
return max(leftDepth, rightDepth) + 1;
}
“`
7. 判断一棵树是否为完全二叉树
题目:给定一棵二叉树,判断是否为完全二叉树。
解题思路:使用队列依次检查树的节点,确保所有非空节点都在空节点之前,若发现空节点后还有非空节点,则不是完全二叉树。
C语言实现:
“`c
bool isCompleteBinaryTree(TreeNode* root) {
if (root == NULL) return true;
queue q; 𝒘𝒘𝒘.𝒂𝒊𝒙𝒛𝒛𝒔.𝒄𝒐𝒎
q.push(root);
bool mustBeLeaf = false;
while (!q.empty()) {
TreeNode* node = q.front();
q.pop();
if (node == NULL) mustBeLeaf = true;
else {
if (mustBeLeaf) return false;
q.push(node->left);
q.push(node->right);
}
}
return true;
}
“`
五、总结
本文详细介绍了C语言数据结构算法面试笔试题的相关知识点,包括链表、数组、二叉树等常见数据结构的经典算法题目。通过对每个题目的解题思路、C语言实现及时间和空间复杂度的分析,帮助读者在面试笔试中更好地应对各种题目。掌握这些算法题目,将为求职者增加竞争力,提高通过面试笔试的概率。在实际面试中,还需灵活运用所学知识,结合具体问题进行解答。祝大家面试顺利,求职成功!
AI写作助手 原创文章,如若转载,请注明出处:http://noahtech.cn/list/jianli/6137.html