diff --git a/exercise/查找.c b/exercise/查找.c new file mode 100644 index 0000000..9ed5138 --- /dev/null +++ b/exercise/查找.c @@ -0,0 +1,330 @@ +#include +#include +#include +#include +#ifdef _WIN32 +#include +#endif + +int MAX = 100000; + +// 二叉排序树节点创建 +struct TreeNode +{ + int val; + int idx; + struct TreeNode *left; + struct TreeNode *right; +}; + +// 顺序查找 +int Linear_Search(int arr[], int size, int target) +{ + for (int i = 0; i < size; i++) + { + if (arr[i] == target) + { + // 返回目标元素的索引 + return i; + } + } + + // 未找到目标元素 + return -1; +} + +// 冒泡排序 +void Bubble_Sort_With_Index(int arr[], int index[], int size) +{ + for (int i = 0; i < size - 1; ++i) + { + int swapped = 0; + for (int j = 0; j < size - 1 - i; ++j) + { + if (arr[j] > arr[j + 1]) + { + int t = arr[j]; + arr[j] = arr[j + 1]; + arr[j + 1] = t; + int ti = index[j]; + index[j] = index[j + 1]; + index[j + 1] = ti; + swapped = 1; + } + } + if (!swapped) + { + break; + } + } +} + +// 二分查找 +int Binary_Search(int arr[], int size, int target) +{ + // 二分查找 + int left = 0; + int right = size - 1; + while (left <= right) + { + int mid = left + (right - left) / 2; + if (arr[mid] == target) + { + // 返回目标元素的索引 + return mid; + } + else if (arr[mid] < target) + { + left = mid + 1; + } + else + { + right = mid - 1; + } + } + + // 未找到目标元素 + return -1; +} + +// 分块查找 +int Block_Search(int arr[], int size, int target) +{ + // 计算分块大小 + int blockSize = (int)sqrt(size); + int start = 0; + int end = blockSize - 1; + + // 分块查找 + while (start < size) + { + if (arr[end] >= target) + { + for (int i = start; i <= end && i < size; i++) + { + if (arr[i] == target) + { + // 返回目标元素的索引 + return i; + } + } + + // 未找到目标元素 + return -1; + } + start += blockSize; + end += blockSize; + if (end >= size) + { + end = size - 1; + } + } + + // 未找到目标元素 + return -1; +} + +// 二叉排序树节点创建 +struct TreeNode *BST_new(int val, int idx) +{ + struct TreeNode *p = (struct TreeNode *)malloc(sizeof(struct TreeNode)); + p->val = val; + p->idx = idx; + p->left = NULL; + p->right = NULL; + return p; +} + +// 二叉排序树节点插入 +struct TreeNode *BST_insert(struct TreeNode *root, int val, int idx) +{ + if (!root) + { + return BST_new(val, idx); + } + struct TreeNode *cur = root; + while (1) + { + // 小于当前节点,向左子树查找 + if (val < cur->val) + { + if (cur->left) + { + cur = cur->left; + } + else + { + cur->left = BST_new(val, idx); + break; + } + } + + // 大于当前节点,向右子树查找 + else if (val > cur->val) + { + if (cur->right) + { + cur = cur->right; + } + else + { + cur->right = BST_new(val, idx); + break; + } + } + + // 等于当前节点,返回当前节点的索引 + else + { + break; + } + } + return root; +} + +// 二叉排序树节点释放 +void BST_free(struct TreeNode *root) +{ + if (!root) + { + return; + } + BST_free(root->left); + BST_free(root->right); + free(root); +} + +// 二叉排序树节点查找 +int BST_Search(struct TreeNode *root, int target) +{ + while (root) + { + if (target == root->val) + { + // 返回目标元素的索引 + return root->idx; + } + if (target < root->val) + { + // 目标元素小于当前节点,向左子树查找 + root = root->left; + } + else + { + // 目标元素大于当前节点,向右子树查找 + root = root->right; + } + } + return -1; +} + +int main(void) +{ +#ifdef _WIN32 + system("chcp 65001 > nul"); + SetConsoleOutputCP(65001); + SetConsoleCP(65001); +#endif + + // 输入整数的个数 + printf("请输入整数的个数(不超过 %d):", MAX); + int n; + scanf("%d", &n); + while (n < 1 || n > MAX) + { + printf("输入的个数不合法!\n"); + scanf("%d", &n); + } + + // 输入整数 + int nums[n]; + printf("请输入 %d 个整数:\n", n); + for (int i = 0; i < n; i++) + { + scanf("%d", &nums[i]); + } + + // 复制排序数组,并记录索引 + int sortedArr[n]; + int indexArr[n]; + for (int i = 0; i < n; i++) + { + sortedArr[i] = nums[i]; + indexArr[i] = i; + } + Bubble_Sort_With_Index(sortedArr, indexArr, n); + + // 打印排序后的数组 + printf("排序后的数组元素为:"); + for (int i = 0; i < n; i++) + { + printf("%d ", sortedArr[i]); + } + printf("\n"); + + while (true) + { + // 查找目标元素 + int target; + int index; + printf("请输入要查找的整数:"); + scanf("%d", &target); + + // 选择查找方法 + printf("请选择查找方法:\n"); + printf("1. 线性查找\n"); + printf("2. 二分查找(数组需有序)\n"); + printf("3. 分块查找(数组需有序)\n"); + printf("4. 二叉搜索树查找\n"); + printf("5. 退出程序\n"); + + // 读取用户选择 + int choice; + scanf("%d", &choice); + + switch (choice) + { + case 1: + index = Linear_Search(nums, n, target); + break; + case 2: + { + int pos = Binary_Search(sortedArr, n, target); + index = (pos != -1) ? indexArr[pos] : -1; + break; + } + case 3: + { + int pos = Block_Search(sortedArr, n, target); + index = (pos != -1) ? indexArr[pos] : -1; + break; + } + case 4: + { + struct TreeNode *root = NULL; + for (int i = 0; i < n; ++i) + { + root = BST_insert(root, nums[i], i); + } + index = BST_Search(root, target); + BST_free(root); + break; + } + case 5: + return 0; + default: + printf("无效的选择,请重新选择。\n"); + continue; + } + + // 输出查找结果 + if (index != -1) + { + printf("找到了,目标元素的索引为:%d\n", index); + } + else + { + printf("未找到目标元素。\n"); + } + } +} \ No newline at end of file diff --git a/exercise/查找.exe b/exercise/查找.exe new file mode 100644 index 0000000..90fec96 Binary files /dev/null and b/exercise/查找.exe differ diff --git a/exercise/模板.txt b/exercise/模板.txt index c9990e8..7da6816 100644 --- a/exercise/模板.txt +++ b/exercise/模板.txt @@ -62,4 +62,62 @@ Windows控制台设置为UTF-8;提示输入n、m与每条边x、y、z;运行 时间与空间复杂度 时间:O(n²) 选择与松弛;空间:邻接矩阵O(n²),辅助数组O(n)。 可能扩展 -改为邻接表+最小堆实现,将复杂度优化为O(m log n);统一输出为OJ格式仅输出数值或-1;增加输入范围校验与路径重建输出。 \ No newline at end of file +改为邻接表+最小堆实现,将复杂度优化为O(m log n);统一输出为OJ格式仅输出数值或-1;增加输入范围校验与路径重建输出。 + +exercise/查找.c 实验分析 + +功能描述 +读取整数个数n与n个整数,复制为sortedArr并用带索引的冒泡排序Bubble_Sort_With_Index排序,同时维护indexArr将排序后位置映射到原数组索引。打印排序结果。随后循环交互读取要查找的整数target与查找方法choice,支持:线性查找、二分查找(在有序数组上)、分块查找(在有序数组上)以及二叉搜索树查找。所有方法统一返回原数组中的索引;二分与分块通过indexArr映射,二叉树通过节点的idx返回。提供“退出程序”选项。 + +数据结构 +数组:nums[n]原始数据;sortedArr[n]排序副本;indexArr[n]排序位置到原索引的映射。 +二叉搜索树:TreeNode { int val; int idx; TreeNode* left; TreeNode* right; }。 +常量:MAX为输入规模上限(100000)。 + +辅助函数 +Linear_Search(arr, size, target):顺序扫描比较。 +Binary_Search(arr, size, target):在有序数组中二分定位并返回位置。 +Block_Search(arr, size, target):按块大小sqrt(size)定位块,块内线性扫描。 +Bubble_Sort_With_Index(arr, index, size):冒泡排序,交换元素同时交换index,实现稳定排序与原索引映射。 +BST_new/BST_insert/BST_free/BST_Search:构建与查找二叉搜索树,查找返回节点idx(原数组索引)。 + +核心算法 +线性查找:从左到右逐项比较。 +二分查找:每轮折半选中点,比较后缩小区间。 +分块查找:按块扫描,先用块尾与目标比较确定块,再在块内线性查找。 +二叉搜索树查找:按值大小关系在树上左/右移动查找。 +预排序:稳定冒泡排序,为二分/分块提供有序数据并维护indexArr以统一索引语义。 + +初始化与交互 +Windows控制台设置为UTF-8。 +读取n与n个整数,完成排序并打印有序数组。 +循环读取target与choice,按菜单执行查找并输出结果;选择5退出程序。 + +输入与输出 +输入:第一行n;随后读入n个整数;之后循环读入查询值与方法选择。 +输出:先打印排序后的数组;每次查询输出“找到了,目标元素的索引为:X”或“未找到目标元素。”。 + +代码特点 +统一索引语义:二分与分块通过indexArr映射回原索引;BST节点直接保存idx。 +稳定排序:仅在arr[j] > arr[j+1]时交换,保持相等元素相对次序。 +使用C99变长数组,简化输入规模驱动的存储。 +BST内存释放完整,避免泄漏;菜单交互支持多次查询与退出。 + +边界与异常处理 +校验n在[1..MAX]范围内。 +二分与分块依赖有序数组,程序已在进入查找前完成排序。 +BST不平衡,最坏情况下退化为链表;重复值只插入第一次出现的节点,查找返回该值的首次出现索引。 +基本输入未做范围与非法字符的深度校验。 + +时间与空间复杂度 +预处理排序:Bubble_Sort_With_Index时间O(n²),额外空间O(n)用于indexArr。 +线性查找:时间O(n),空间O(1)。 +二分查找:时间O(log n),空间O(1);返回某一匹配位置的原索引(不保证最左)。 +分块查找:时间O(√n)(定位块O(√n)+块内线性扫描O(√n)),空间O(1);通常返回该块内第一个匹配的原索引。 +二叉搜索树查找:平均时间O(log n),最坏O(n);空间O(n)(节点)。 +整体空间:数组O(n),BST O(n)。 + +可能扩展 +将预排序替换为快速排序或qsort,将预处理复杂度优化为O(n log n)。 +使用平衡BST或哈希表提高查找性能与一致性;二分查找改为返回最左/最右匹配以满足特定需求。 +增加输入范围校验、异常处理与批量查询支持。 \ No newline at end of file