This commit is contained in:
2026-01-22 21:43:03 +08:00
parent 1398ae9e17
commit 84fd6d7a92
3 changed files with 389 additions and 1 deletions
+330
View File
@@ -0,0 +1,330 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdbool.h>
#ifdef _WIN32
#include <windows.h>
#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");
}
}
}
Binary file not shown.
+58
View File
@@ -63,3 +63,61 @@ Windows控制台设置为UTF-8;提示输入n、m与每条边x、y、z;运行
时间:O(n²) 选择与松弛;空间:邻接矩阵O(n²),辅助数组O(n)。
可能扩展
改为邻接表+最小堆实现,将复杂度优化为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或哈希表提高查找性能与一致性;二分查找改为返回最左/最右匹配以满足特定需求。
增加输入范围校验、异常处理与批量查询支持。