更新
This commit is contained in:
+330
@@ -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.
+59
-1
@@ -62,4 +62,62 @@ Windows控制台设置为UTF-8;提示输入n、m与每条边x、y、z;运行
|
||||
时间与空间复杂度
|
||||
时间:O(n²) 选择与松弛;空间:邻接矩阵O(n²),辅助数组O(n)。
|
||||
可能扩展
|
||||
改为邻接表+最小堆实现,将复杂度优化为O(m log n);统一输出为OJ格式仅输出数值或-1;增加输入范围校验与路径重建输出。
|
||||
改为邻接表+最小堆实现,将复杂度优化为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或哈希表提高查找性能与一致性;二分查找改为返回最左/最右匹配以满足特定需求。
|
||||
增加输入范围校验、异常处理与批量查询支持。
|
||||
Reference in New Issue
Block a user