链表的解题思路与流程:
1. 定义链表节点的结构体,包括节点值和指向下一个节点的指针。
```c
struct ListNode {
int val;
struct ListNode* next;
};
```
2. 创建链表对象,可以使用循环或递归方式。可以根据具体问题的需求来决定创建链表的方式。
3. 链表的基本操作包括插入节点、删除节点和查找节点。
- 插入节点:创建新节点并将其指针指向前一个节点,将前一个节点的指针指向新节点,将新节点的指针指向下一个节点即可。
```c
void insertNode(struct ListNode* node, int value) {
struct ListNode* new_node = (struct ListNode*)malloc(sizeof(struct ListNode));
new_node->val = value;
new_node->next = node->next;
node->next = new_node;
}
```
- 删除节点:找到要删除的节点的前一个节点,将其指针指向要删除节点的下一个节点,然后释放要删除的节点。
```c
struct ListNode* deleteNode(struct ListNode* head, int target) {
if (head && head->val == target) {
struct ListNode* new_head = head->next;
free(head);
return new_head;
}
struct ListNode* node = head;
while (node->next) {
if (node->next->val == target) {
struct ListNode* temp = node->next;
node->next = node->next->next;
free(temp);
break;
}
node = node->next;
}
return head;
}
```
- 查找节点:从头节点开始遍历链表,比较每个节点的值与目标值,直到找到目标节点或到达链表末尾。
```c
int findNode(struct ListNode* head, int target) {
struct ListNode* node = head;
while (node) {
if (node->val == target) {
return 1;
}
node = node->next;
}
return 0;
}
```
4. 链表的常见问题类型包括反转链表、合并链表、判断链表是否有环等。
- 反转链表:使用三个指针分别指向当前节点、前一个节点和下一个节点,反转指针的指向即可。
```c
struct ListNode* reverseList(struct ListNode* head) {
struct ListNode *prev = NULL, *curr = head;
while (curr) {
struct ListNode* next_node = curr->next;
curr->next = prev;
prev = curr;
curr = next_node;
}
return prev;
}
```
- 合并链表:使用两个指针分别指向两个链表的头节点,比较节点值大小,将较小的节点连接到新链表中,移动指针继续比较。
```c
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2) {
if (!l1)
return l2;
if (!l2)
return l1;
struct ListNode* new_head;
if (l1->val < l2->val) {
new_head = l1;
new_head->next = mergeTwoLists(l1->next, l2);
}
else {
new_head = l2;
new_head->next = mergeTwoLists(l1, l2->next);
}
return new_head;
}
```
- 判断链表是否有环:使用快慢指针,快指针每次移动两步,慢指针每次移动一步,如果存在环,两个指针会在某一节点相遇。若快指针能到达链表末尾,则无环。
```c
int hasCycle(struct ListNode* head) {
if (!head || !head->next)
return 0;
struct ListNode* slow = head;
struct ListNode* fast = head;
while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
if (slow == fast)
return 1;
}
return 0;
}
```
树的解题思路与流程:
1. 定义树节点的结构体,包括节点值和左右子节点的指针。
```c
struct TreeNode {
int val;
struct TreeNode* left;
struct TreeNode* right;
};
```
2. 创建树对象,可以使用递归或迭代方式。可以根据具体问题的需求来决定创建树的方式。
3. 树的基本操作包括插入节点、删除节点和查找节点。
- 插入节点:找到节点要插入的位置,创建新节点并将其挂载到对应位置的子节点上。
```c
void insertNode(struct TreeNode** root, int value) {
if (*root == NULL) {
struct TreeNode* new_node = (struct TreeNode*)malloc(sizeof(struct TreeNode));
new_node->val = value;
new_node->left = NULL;
new_node->right = NULL;
*root = new_node;
}
else if (value < (*root)->val) {
insertNode(&(*root)->left, value);
}
else {
insertNode(&(*root)->right, value);
}
}
```
- 删除节点:分为三种情况处理:删除叶子节点、删除只有一个子节点的节点、删除有两个子节点的节点。具体操作可以是将子节点移动至删除节点的位置,然后释放删除节点。
```c
struct TreeNode* deleteNode(struct TreeNode* root, int key) {
if (root == NULL)
return root;
if (key < root->val)
root->left = deleteNode(root->left, key);
else if (key > root->val)
root->right = deleteNode(root->right, key);
else {
if (root->left == NULL) {
struct TreeNode* temp = root->right;
free(root);
return temp;
}
else if (root->right == NULL) {
struct TreeNode* temp = root->left;
free(root);
return temp;
}
struct TreeNode* min_node = findMinNode(root->right);
root->val = min_node->val;
root->right = deleteNode(root->right, min_node->val);
}
return root;
}
struct TreeNode* findMinNode(struct TreeNode* root) {
while (root && root->left)
root = root->left;
return root;
}
```
- 查找节点:从根节点开始递归或迭代遍历树,比较每个节点的值与目标值,直到找到目标节点或到达叶子节点。
```c
struct TreeNode* findNode(struct TreeNode* root, int target) {
if (root == NULL || root->val == target)
return root;
if (target < root->val)
return findNode(root->left, target);
else
return findNode(root->right, target);
}
```
4. 树的常见问题类型包括前序遍历、中序遍历、后序遍历、层序遍历等。
- 前序遍历:先输出当前节点的值,再依次遍历左子树和右子树。
```c
void preorderTraversal(struct TreeNode* root) {
if (root) {
printf("%d ", root->val);
preorderTraversal(root->left);
preorderTraversal(root->right);
}
}
```
- 中序遍历:先遍历左子树,再输出当前节点的值,最后遍历右子树。
```c
void inorderTraversal(struct TreeNode* root) {
if (root) {
inorderTraversal(root->left);
printf("%d ", root->val);
inorderTraversal(root->right);
}
}
```
- 后序遍历:先遍历左子树,再遍历右子树,最后输出当前节点的值。
```c
void postorderTraversal(struct TreeNode* root) {
if (root) {
postorderTraversal(root->left);
postorderTraversal(root->right);
printf("%d ", root->val);
}
}
```
- 层序遍历:按层次从上到下、从左到右的顺序遍历树,使用队列来实现。
```c
void levelOrder(struct TreeNode* root) {
if (root == NULL)
return;
struct TreeNode* queue[1000];
int front = 0, rear = 0;
queue[rear] = root;
rear++;
while (front < rear) {
struct TreeNode* node = queue[front];
front++;
printf("%d ", node->val);
if (node->left) {
queue[rear] = node->left;
rear++;
}
if (node->right) {
queue[rear] = node->right;
rear++;
}
}
}