目录
一、实验目的
- 掌握常用查找方法的基本思想及其实现技术;
- 了解各种查找方法的优缺点和适用范围,能对相关的算法进行性能分析
- 掌握常用排序方法的基本思想及其实现技术。
- 了解各种排序方法的优缺点和适用范围,能对相关的算法进行性能分析
二、实验要求
- 设计一个可实现各种查找的演示程序(如学生信息表)。
- 设计一个可实现各种排序的演示程序(如学生信息表)
方法提示:用顺序表存储,学生信息表可以直接从某个文件中导入。
参考数据结构(在实验2的基础上进行查找和排序)
typedef struct
{ char no[10];
char name[10];
int score[5];
int total;
}student;
typedef struct
{
student stu[MAXSIZE];
int len;
}SeqList;
1. 实现下列六种查找:(1)顺序查找;(2)二分查找;(3)二叉排序树的查找;(必须实现顺序查找)
2. 实现下列六种排序:(1)冒泡;(2)直接插入排序;(3)选择排序;(4)快速排序; (5)希尔排序 ;(6)堆排序(至少实现2种排序算法)
三、核心代码
二分查找
int BinarySearch(SeqList *list, char *name) {
int low = 0;
int high = list->len - 1;
while (low <= high) {
int mid = low + (high - low) / 2;
int res = strcmp(list->stu[mid].name, name);
if (res == 0) {
return mid; // 找到
} else if (res < 0) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return -1; // 未找到
}
二叉排序树的插入
TreeNode* InsertTreeNode(TreeNode *root, student data) {
if (root == NULL) {
root = (TreeNode*)malloc(sizeof(TreeNode));
root->data = data;
root->left = root->right = NULL;
} else if (strcmp(data.name, root->data.name) < 0) {
root->left = InsertTreeNode(root->left, data);
} else {
root->right = InsertTreeNode(root->right, data);
}
return root;
}
二叉排序树的查找
TreeNode* SearchTreeNode(TreeNode *root, char *name) {
if (root == NULL || strcmp(root->data.name, name) == 0) {
return root;
}
if (strcmp(name, root->data.name) < 0) {
return SearchTreeNode(root->left, name);
} else {
return SearchTreeNode(root->right, name);
}
}
堆排序的辅助函数
void Heapify(student arr[], int n, int i) {
int largest = i;
int left = 2 * i + 1;
int right = 2 * i + 2;
if (left < n && strcmp(arr[left].name, arr[largest].name) > 0)
largest = left;
if (right < n && strcmp(arr[right].name, arr[largest].name) > 0)
largest = right;
if (largest != i) {
student swap = arr[i];
arr[i] = arr[largest];
arr[largest] = swap;
Heapify(arr, n, largest);
}
}
堆排序
void HeapSort(SeqList *list) {
int n = list->len;
int i;
for (i = n / 2 - 1; i >= 0; i--)
Heapify(list->stu, n, i);
for (i = n - 1; i > 0; i--) {
student temp = list->stu[0];
list->stu[0] = list->stu[i];
list->stu[i] = temp;
Heapify(list->stu, i, 0);
}
}
快速排序的辅助函数
int Partition(student arr[], int low, int high) {
student pivot = arr[high];
int i = (low - 1);
int j;
for (j = low; j <= high - 1; j++) {
if (strcmp(arr[j].name, pivot.name) < 0) {
i++;
student temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
student temp = arr[i + 1];
arr[i + 1] = arr[high];
arr[high] = temp;
return (i + 1);
}
快速排序
void QuickSort(student arr[], int low, int high) {
if (low < high) {
int pi = Partition(arr, low, high);
QuickSort(arr, low, pi - 1);
QuickSort(arr, pi + 1, high);
}
}
四、实验记录
实验时输入多组测试数据,粘贴运行结果截图
(1) 学生信息表直接从学生信息表文件中导入,学生信息可以进行修改。进行aa学生的序号查找以及序号查找学生姓名的操作。实现顺序查找以及二分查找、二叉排序树查找。
(2) 对学生信息表实现排序功能,进行希尔排序、堆排序、快速排序的功能。
五、总结
1、查找方法
(1)顺序查找:从列表的第一个元素开始,逐个比较,直到找到目标元素或遍历完整个列表。时间复杂度为O(n)。
(2)二分查找:在有序列表中,取中间元素进行比较,如果目标值等于中间元素,则查找成功;如果目标值小于中间元素,则在左半部分继续查找;如果目标值大于中间元素,则在右半部分继续查找。时间复杂度为O( )。
(3)二叉排序树的查找:在二叉排序树中,根据目标值的大小,选择左子树或右子树进行查找。时间复杂度为O( )到O(n)。
2、排序方法
(1)冒泡排序:通过相邻元素之间的比较和交换,使得每一趟循环都能将最大(或最小)的元素放到正确的位置。时间复杂度为O(n^2)。
(2)直接插入排序:将待排序的元素插入到已排序的序列中的适当位置,使得插入后的序列仍然有序。时间复杂度为O(n^2)。
(3)选择排序:每次从未排序的元素中找出最小(或最大)的元素,将其放到已排序序列的末尾。时间复杂度为O(n^2)。
(4)快速排序:采用分治法,将待排序的序列分为两部分,一部分是小于基准值的元素,另一部分是大于基准值的元素,然后对这两部分分别进行快速排序。时间复杂度为O(nlogn)。
(5)希尔排序:先将待排序的序列按照一定的间隔分组,对每组进行插入排序,然后逐渐减小间隔,重复上述过程,直到间隔为1,此时整个序列已经有序。时间复杂度为O(n^(3/2))。
(6)堆排序:利用堆这种数据结构,将待排序的序列构造成一个大顶堆或小顶堆,然后将堆顶元素与最后一个元素交换,再调整堆的结构,重复上述过程,直到整个序列有序。时间复杂度为O( )。
六、完整报告和成果文件提取链接
完整可运行代码以及相关实验报告以下链接可获取:
链接:https://pan.baidu.com/s/1DuGfYm6_KDm04gUKWFSSVQ?pwd=lw6u
提取码:lw6u