算法设计题(查找)

1.设单向链表的结点是按关键字从小到大排列的,试写出对此链表进行查找的算
如果查找成功,则返回指向关键字为 的结点的指针,否则返回NUIl

思路:

1. 定义链表节点的结构体
typedef struct Node {
    int key;           // 节点中存储的数据
    struct Node* next; // 指向下一个节点的指针
} Node;

  • key:节点中存储的数据,这里是一个 int 类型的值。
  • next:指向下一个节点的指针,用于连接链表中的节点。
2. 查找特定值的函数 FindList
Node* FindList(Node* head, int target) {
    Node* cur = head; // 当前节点指针,初始化为链表头节点
    while (cur != NULL) { // 遍历链表直到结束
        // 如果找到目标值,返回该节点
        if (cur->key == target) {
            return cur;
        }
        // 如果当前节点的值大于目标值,说明目标值不在链表中,返回 NULL
        else if (cur->key > target) {
            return NULL;
        }
        cur = cur->next; // 移动到下一个节点
    }
    return NULL; // 如果遍历完链表未找到目标值,返回 NULL
}

  • 功能:在有序链表中查找特定值 target
  • 流程
    1. 从链表的头节点开始遍历。
    2. 如果当前节点的值等于目标值,返回该节点。
    3. 如果当前节点的值大于目标值,说明目标值不在链表中,返回 NULL
    4. 继续遍历下一个节点,直到链表结束。
    5. 如果遍历完链表未找到目标值,返回 NULL
3. 创建新节点的函数 createNode
Node* createNode(int key) {
    Node* newNode = (Node*)malloc(sizeof(Node)); // 分配内存给新节点
    if (newNode == NULL) { // 检查内存分配是否成功
        printf("内存分配失败\n");
        exit(1);
    }
    newNode->key = key;   // 设置新节点的值
    newNode->next = NULL; // 新节点的下一个节点指针初始化为 NULL
    return newNode;       // 返回新节点
}

  • 功能:创建一个新节点,并初始化其值为 key
  • 流程
    1. 使用 malloc 分配内存给新节点。
    2. 检查内存分配是否成功,如果失败则输出错误信息并退出程序。
    3. 设置新节点的值为 key
    4. 初始化新节点的下一个节点指针为 NULL
    5. 返回新节点。
4. 向链表中插入节点并保持链表有序的函数 insetNode
void insetNode(Node** head, int key) {
    Node* newNode = createNode(key); // 创建新节点
    if (*head == NULL || key < (*head)->key) {
        // 如果链表为空或者新节点的值小于头节点的值,将新节点插入到链表头部
        newNode->next = *head; // 新节点的下一个节点指针指向当前头节点
        *head = newNode;       // 更新头节点为新节点
    } else {
        Node* cur = *head; // 当前节点指针,初始化为链表头节点
        while (cur->next != NULL && key > cur->next->key) {
            // 找到合适的位置插入新节点
            cur = cur->next; // 移动到下一个节点
        }
        newNode->next = cur->next; // 新节点的下一个节点指针指向当前节点的下一个节点
        cur->next = newNode;       // 当前节点的下一个节点指针指向新节点
    }
}

  • 功能:将新节点插入到有序链表中,并保持链表有序。
  • 流程
    1. 创建新节点。
    2. 如果链表为空或者新节点的值小于头节点的值,将新节点插入到链表头部。
    3. 否则,从链表头部开始遍历,找到合适的位置插入新节点(即新节点的值大于当前节点的值但小于下一个节点的值)。
    4. 更新节点的指针,将新节点插入到链表中。
5. 释放链表内存的函数 freeList
void freeList(Node* head) {
    Node* current = head; // 当前节点指针,初始化为链表头节点
    while (current != NULL) { // 遍历链表直到结束
        Node* next = current->next; // 保存下一个节点的指针
        free(current);              // 释放当前节点的内存
        current = next;             // 移动到下一个节点
    }
}

  • 功能:释放链表中所有节点的内存。
  • 流程
    1. 从链表的头节点开始遍历。
    2. 保存当前节点的下一个节点的指针。
    3. 释放当前节点的内存。
    4. 移动到下一个节点,继续遍历直到链表结束。
6. 主函数 main
int main() {
    Node* head = NULL; // 初始化链表头指针为 NULL

    // 向链表中插入一些有序的值
    insetNode(&head, 2);
    insetNode(&head, 4);
    insetNode(&head, 9);
    insetNode(&head, 6);
    insetNode(&head, 8);
    insetNode(&head, 10);

    int target = 6; // 要查找的目标值
    Node* result = FindList(head, target); // 在链表中查找目标值

    if (result != NULL) {
        // 如果找到目标值,输出提示信息
        printf("找到链表关键字 %d\n", target);
    } else {
        // 如果未找到目标值,输出提示信息
        printf("没有找到链表关键字 %d\n", target);
    }

    // 释放链表内存
    freeList(head);

    return 0;
}

  • 功能:初始化链表,插入一些有序的值,查找特定值,释放链表内存。
  • 流程
    1. 初始化链表头指针为 NULL
    2. 调用 insetNode 函数向链表中插入一些有序的值。
    3. 设定要查找的目标值。
    4. 调用 FindList 函数在链表中查找目标值,并根据查找结果输出提示信息。
    5. 调用 freeList 函数释放链表内存。
    6. 返回 0,表示程序正常结束。

代码:

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

// 定义链表节点的结构体
typedef struct Node {
    int key;           // 节点中存储的数据
    struct Node* next; // 指向下一个节点的指针
} Node;

// 在链表中查找特定值的函数
Node* FindList(Node* head, int target) {
    Node* cur = head; // 当前节点指针,初始化为链表头节点
    while (cur != NULL) { // 遍历链表直到结束
        // 如果找到目标值,返回该节点
        if (cur->key == target) {
            return cur;
        }
        // 如果当前节点的值大于目标值,说明目标值不在链表中,返回 NULL
        else if (cur->key > target) {
            return NULL;
        }
        cur = cur->next; // 移动到下一个节点
    }
    return NULL; // 如果遍历完链表未找到目标值,返回 NULL
}

// 创建新节点的函数
Node* createNode(int key) {
    Node* newNode = (Node*)malloc(sizeof(Node)); // 分配内存给新节点
    if (newNode == NULL) { // 检查内存分配是否成功
        printf("内存分配失败\n");
        exit(1);
    }
    newNode->key = key;   // 设置新节点的值
    newNode->next = NULL; // 新节点的下一个节点指针初始化为 NULL
    return newNode;       // 返回新节点
}

// 向链表中插入节点并保持链表有序的函数
void insetNode(Node** head, int key) {
    Node* newNode = createNode(key); // 创建新节点
    if (*head == NULL || key < (*head)->key) {
        // 如果链表为空或者新节点的值小于头节点的值,将新节点插入到链表头部
        newNode->next = *head; // 新节点的下一个节点指针指向当前头节点
        *head = newNode;       // 更新头节点为新节点
    } else {
        Node* cur = *head; // 当前节点指针,初始化为链表头节点
        while (cur->next != NULL && key > cur->next->key) {
            // 找到合适的位置插入新节点
            cur = cur->next; // 移动到下一个节点
        }
        newNode->next = cur->next; // 新节点的下一个节点指针指向当前节点的下一个节点
        cur->next = newNode;       // 当前节点的下一个节点指针指向新节点
    }
}

// 释放链表内存的函数
void freeList(Node* head) {
    Node* current = head; // 当前节点指针,初始化为链表头节点
    while (current != NULL) { // 遍历链表直到结束
        Node* next = current->next; // 保存下一个节点的指针
        free(current);              // 释放当前节点的内存
        current = next;             // 移动到下一个节点
    }
}

int main() {
    Node* head = NULL; // 初始化链表头指针为 NULL

    // 向链表中插入一些有序的值
    insetNode(&head, 2);
    insetNode(&head, 4);
    insetNode(&head, 9);
    insetNode(&head, 6);
    insetNode(&head, 8);
    insetNode(&head, 10);

    int target = 6; // 要查找的目标值
    Node* result = FindList(head, target); // 在链表中查找目标值

    if (result != NULL) {
        // 如果找到目标值,输出提示信息
        printf("找到链表关键字 %d\n", target);
    } else {
        // 如果未找到目标值,输出提示信息
        printf("没有找到链表关键字 %d\n", target);
    }

    // 释放链表内存
    freeList(head);

    return 0;
}


2.试设计一个算法,求出指定结点在给定的二叉搜索树中所在的层次。

下面题目建立的二叉搜索树结构
        50
       /  \
     30    70
    /  \  /  \
  20   40 60  80

 思路:

1. 定义二叉树结点

首先,我们需要定义一个表示二叉树结点的结构体TreeNode,包含以下成员:

  • int val:结点的值。
  • TreeNode* left:指向左子树的指针。
  • TreeNode* right:指向右子树的指针。
typedef struct TreeNode {
    int val;
    struct TreeNode* left;
    struct TreeNode* right;
} TreeNode;

2. 创建新结点

为了在二叉搜索树中插入新结点,我们需要一个函数createNode来创建新的结点并初始化其值和左右子树指针。

TreeNode* createNode(int val) {
    TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode));
    newNode->val = val;
    newNode->left = NULL;
    newNode->right = NULL;
    return newNode;
}

3. 插入结点到二叉搜索树

插入操作是二叉搜索树的核心操作之一。我们需要根据结点的值来决定将其插入到左子树还是右子树。递归是实现插入操作的一种常见方式。

TreeNode* insert(TreeNode* root, int val) {
    if (root == NULL) {
        return createNode(val);
    }
    if (val < root->val) {
        root->left = insert(root->left, val);
    } else if (val > root->val) {
        root->right = insert(root->right, val);
    }
    return root;
}

4. 查找结点的层次

查找结点的层次也是通过递归实现的。我们从根结点开始,逐层向下查找,直到找到目标结点或者确定结点不存在。

int findLevel(TreeNode* root, int key, int level) {
    if (root == NULL) {
        return -1;
    }
    if (root->val == key) {
        return level;
    }
    int leftLevel = findLevel(root->left, key, level + 1);
    if (leftLevel != -1) {
        return leftLevel;
    }
    return findLevel(root->right, key, level + 1);
}

5. 打印二叉树(中序遍历)

中序遍历是一种常见的二叉树遍历方式,输出结果是有序的。我们通过递归实现中序遍历。

void inorderTraversal(TreeNode* root) {
    if (root != NULL) {
        inorderTraversal(root->left);
        printf("%d ", root->val);
        inorderTraversal(root->right);
    }
}

6. 释放二叉树内存

为了避免内存泄漏,我们需要在程序结束前释放二叉树的所有结点。同样,我们通过递归实现。

void freeTree(TreeNode* root) {
    if (root != NULL) {
        freeTree(root->left);
        freeTree(root->right);
        free(root);
    }
}

7. 主函数

在主函数中,我们完成以下操作:

  • 初始化根结点。
  • 插入一系列结点。
  • 打印二叉搜索树的中序遍历结果。
  • 查找指定结点的层次并输出结果。
  • 释放二叉树的内存。
int main() {
    TreeNode* root = NULL;

    // 插入元素
    root = insert(root, 50);
    root = insert(root, 30);
    root = insert(root, 20);
    root = insert(root, 40);
    root = insert(root, 70);
    root = insert(root, 60);
    root = insert(root, 80);

    printf("二叉搜索树的中序遍历结果:\n");
    inorderTraversal(root);
    printf("\n");

    // 查找指定结点的层次
    int key = 60;
    int level = findLevel(root, key, 1);
    if (level != -1) {
        printf("结点 %d 在第 %d 层\n", key, level);
    } else {
        printf("结点 %d 未找到\n", key);
    }

    // 释放二叉树内存
    freeTree(root);

    return 0;
}

代码:

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

// 定义二叉树结点
typedef struct TreeNode {
    int val;  // 结点值
    struct TreeNode* left;  // 左子树指针
    struct TreeNode* right;  // 右子树指针
} TreeNode;

// 创建新结点
TreeNode* createNode(int val) {
    TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode));  // 分配内存
    newNode->val = val;  // 设置结点值
    newNode->left = NULL;  // 初始化左子树为空
    newNode->right = NULL;  // 初始化右子树为空
    return newNode;  // 返回新结点
}

// 插入结点到二叉搜索树
TreeNode* insert(TreeNode* root, int val) {
    if (root == NULL) {  // 如果树为空
        return createNode(val);  // 创建并返回新结点
    }
    if (val < root->val) {  // 如果插入值小于当前结点值
        root->left = insert(root->left, val);  // 插入到左子树
    } else if (val > root->val) {  // 如果插入值大于当前结点值
        root->right = insert(root->right, val);  // 插入到右子树
    }
    return root;  // 返回根结点
}

// 查找结点在二叉搜索树中的层次
int findLevel(TreeNode* root, int key, int level) {
    if (root == NULL) {  // 如果树为空
        return -1;  // 结点不存在
    }
    if (root->val == key) {  // 如果找到结点
        return level;  // 返回当前层次
    }
    int leftLevel = findLevel(root->left, key, level + 1);  // 在左子树中查找
    if (leftLevel != -1) {  // 如果在左子树中找到结点
        return leftLevel;  // 返回左子树中的层次
    }
    return findLevel(root->right, key, level + 1);  // 在右子树中查找
}

// 打印二叉树(中序遍历)
void inorderTraversal(TreeNode* root) {
    if (root != NULL) {  // 如果结点不为空
        inorderTraversal(root->left);  // 遍历左子树
        printf("%d ", root->val);  // 打印当前结点值
        inorderTraversal(root->right);  // 遍历右子树
    }
}

// 释放二叉树内存
void freeTree(TreeNode* root) {
    if (root != NULL) {  // 如果结点不为空
        freeTree(root->left);  // 释放左子树
        freeTree(root->right);  // 释放右子树
        free(root);  // 释放当前结点
    }
}

int main() {
    TreeNode* root = NULL;  // 初始化根结点为空

    // 插入元素
    root = insert(root, 50);
    root = insert(root, 30);
    root = insert(root, 20);
    root = insert(root, 40);
    root = insert(root, 70);
    root = insert(root, 60);
    root = insert(root, 80);

    printf("二叉搜索树的中序遍历结果:\n");
    inorderTraversal(root);
    printf("\n");

    // 查找指定结点的层次
    int key = 60;
    int level = findLevel(root, key, 1);  // 从根结点开始,层次为1
    if (level != -1) {
        printf("结点 %d 在第 %d 层\n", key, level);
    } else {
        printf("结点 %d 未找到\n", key);
    }

    // 释放二叉树内存
    freeTree(root);

    return 0;
}


3.利用二分查找算法,编写一个在有序表中插入一个元素X,并保持表仍然有序的

思路:

  1. 二分查找函数 binarySearch:

    • 使用二分查找算法在有序表中查找元素 x
    • 如果找到元素 x,返回该元素的索引。
    • 如果没有找到元素 x,返回插入位置的索引(即 left)。
  2. 插入元素函数 insertElement:

    • 调用 binarySearch 函数找到插入位置 insertPos
    • 从插入位置开始,将后续元素依次后移一位,为新元素腾出空间。
    • 将新元素插入到 insertPos 位置。
    • 增加表的大小 *size
  3. 主函数 main:

    • 初始化一个有序表 arr 和当前表的大小 size
    • 打印初始有序表。
    • 调用 insertElement 函数插入新元素。
    • 打印插入新元素后的有序表。

代码:

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

// 二分查找算法,返回插入位置的索引
int binarySearch(int arr[], int left, int right, int x) {
    while (left <= right) {
        int mid = left + (right - left) / 2;  // 计算中间位置
        if (arr[mid] == x) {
            return mid;  // 如果找到了元素,返回该位置
        } else if (arr[mid] < x) {
            left = mid + 1;  // 目标元素在右半部分
        } else {
            right = mid - 1;  // 目标元素在左半部分
        }
    }
    return left;  // 如果没有找到元素,返回插入位置
}

// 插入元素到有序表中
void insertElement(int arr[], int *size, int x) {
    int insertPos = binarySearch(arr, 0, *size - 1, x);  // 找到插入位置
    for (int i = *size; i > insertPos; i--) {
        arr[i] = arr[i - 1];  // 从插入位置开始,将后续元素依次后移一位
    }
    arr[insertPos] = x;  // 将新元素插入到插入位置
    (*size)++;  // 增加表的大小
}

int main() {
    int arr[100] = {10, 20, 30, 40, 50, 60, 70, 80};  // 初始有序表
    int size = 8;  // 当前表的大小

    printf("初始有序表: ");
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);  // 打印初始有序表
    }
    printf("\n");

    int x = 45;  // 需要插入的元素
    insertElement(arr, &size, x);  // 插入新元素

    printf("插入元素 %d 后的有序表: ", x);
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);  // 打印插入新元素后的有序表
    }
    printf("\n");

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值