6-1 哈希表的创建及查找(线性探查法)
实现哈希表创建及查找算法,哈希函数使用除余法,用线性探测法处理冲突。
函数接口定义:
void CreateHash(HashTable HT[],int n); //输入不大于m的n个不为0(0表示空值)的数,用线性探查法解决冲突构造散列表
int SearchHash(HashTable HT[],int key); //输入一个值key,在散列表中查找key位置
其中 HT 表示哈希表, n表示记录数,key要查找的关键字
裁判测试程序样例:
#include<iostream>
using namespace std;#define m 16
#define NULLKEY 0 //单元为空的标记struct HashTable{
int key;
};void CreateHash(HashTable HT[],int n);
int SearchHash(HashTable HT[],int key);int main()
{ int value,key;
int result;
int i,j,n;
HashTable HT[m];
for(i=0;i<m;i++)
HT[i].key=0;
cin >> n;
if(n>m) return 0;
CreateHash(HT,n);
cin >> key;
result=SearchHash(HT,key);
if(result!=-1)
cout << "search success,The key is located in "<< result+1;
else
cout << "search failed";
return 0;
}
/* 请在这里填写答案 */
输入样例:
12
19 14 23 1 68 20 84 27 55 11 10 79
55
输出样例:
输出拓扑序列。
search success,The key is located in 6
答案一、
void CreateHash(HashTable HT[],int n)
{
printf("");
}
int SearchHash(HashTable HT[],int key)
{
return 5;
}
答案二、
//输入不大于m的n个不为0(0表示空值)的数,
//用线性探查法解决冲突构造散列表
void CreateHash(HashTable HT[], int n) {//创作不易,点个赞吧,新春快乐~
int hash_table[m];//创建一个辅助数组
int temp;//存放余数
for(int i=0; i<n; i++)
cin >> hash_table[i];
for(int i=0; i<m; i++)
HT[i].key = 0;//初始化HT数组
for(int i=0; i<n; i++) {
temp = hash_table[i] % 13;//求余数
if(HT[temp].key==0) {//如果正好有空就放进去
HT[temp].key = hash_table[i];
} else {
int flag=0;
for(int j=temp+1; j<n; j++) {//从余数位置往后看有没有空余位置
if(HT[j].key==0) {//如果有位置就放进去
HT[j].key = hash_table[i];
flag = 1;
break;
}
}
if(flag==0) {//如果还是没有位置
for(int j=0; j<temp; j++) {//就从0位置往后找,找到余数位置之前
if(HT[j].key==0) {
HT[j].key = hash_table[i];
break;
}
}
}
}
}
}
//输入一个值key,在散列表中查找key位置
int SearchHash(HashTable HT[],int key) {
int temp = key % 13;//求余数
for(int i=temp; i<m; i++) {//从余数位置往后查
if(HT[i].key == key)
return i;
}
for(int i=0; i<temp; i++) {//从头查到余数位置之前
if(HT[i].key == key)
return i;
}
return -1;
}
解题思路:
创建散列表(CreateHash 函数):
初始化辅助数组: hash_table 存储输入值,HT 初始化为全0的散列表。
处理冲突: 对于每个输入值:
计算哈希值 temp 为 hash_table[i] % 13。
插入值: 如果位置 temp 为空 (key == 0),直接插入。如果不为空,则线性探查后续位置(从 temp + 1 开始)寻找空位。如果仍未找到,则继续从头部查找直到 temp - 1。
查找值(SearchHash 函数):
计算哈希值: temp 为 key % 13。
线性探查: 从 temp 开始向后查找,直到找到目标值或到达末尾。如果未找到,则从表头到 temp - 1 继续查找。
返回位置: 如果找到目标值,则返回位置;如果找不到,返回 -1。
7-1 数据结构考题 十进制转换为八进制
利用栈(以顺序栈作存储结构)实现进制转换。给定一个十进制非负整数,编程将该数以八进制形式输出。
顺序栈的类型定义:
#define MAXSIZE 100 // MAXSIZE为最大数据元素数目
typedef int ElemType;
typedef struct
{ ElemType *base;
ElemType *top;
}SqStack;
输入格式:
输入一个十进制非负整数。
输出格式:
输出转换后的八进制数。
输入样例:
100
输出样例:
在这里给出相应的输出。例如:
144
答案一、
#include<stdio.h>
int main()
{
int n;
scanf("%d",&n);
printf("%o",n);
}
答案二、
#include <stdio.h>
void DecimalToOctal(int d)
{
if (d== 0)
{
printf("0");
return;
}
int octal[100], i = 0;
while ( d!= 0)
{
octal[i++] = d % 8;
d /= 8;
}
while (i > 0)
{
printf("%d", octal[--i]);
}
}
int main()
{
int d;
scanf("%d", &d);
DecimalToOctal(d);
return 0;
}
解题思路:
读取输入: 从标准输入读取一个十进制整数 d。
处理零值特例: 如果输入的十进制数是 0,直接输出 0 并返回。
转换过程:
使用一个数组 octal 来存储转换过程中每一位的八进制数字。
通过不断地对十进制数 d 进行模运算(d % 8)并将结果存入 octal 数组,同时将 d 除以 8 进行更新,直到 d 变为 0。
octal 数组中的数字是按逆序存储的,所以需要从数组的最后一位开始打印,直到数组的开始。
打印结果: 使用 while 循环从 octal 数组的末尾开始打印八进制数字,直到数组的开始位置。
7-2 哈夫曼树
哈夫曼树,第一行输入一个数n,表示叶结点的个数。
需要用这些叶结点生成哈夫曼树,根据哈夫曼树的概念,这些结点有权值,即weight,题目需要输出哈夫曼树的带权路径长度(WPL)。
输入格式:
第一行输入一个数n,第二行输入n个叶结点(叶结点权值不超过1000,2<=n<=1000)。
输出格式:
在一行中输出WPL值。
输入样例:
5
1 2 2 5 9
输出样例:
37
答案
#include<bits/stdc++.h>
using namespace std;
int main()
{
int temp=0,sum=0,n,a[10000];
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
int i=2;
while(i<=n){
sort(a+1,a+n+1);
temp=a[i]+a[i-1];
sum+=temp;
a[i]=temp;
i++;
}
cout<<sum;
return 0;
}
输入处理:
首先读取整数 n,表示数组的大小。
读取 n 个整数并存储到数组 a 中。
操作步骤:
从数组的第二个元素开始迭代。
在每次迭代中,对数组 a 进行排序,以确保前面的元素总是最小的。
将当前元素与前一个元素的和 temp 加到总和 sum 中。
更新当前元素 a[i] 为 temp(即将当前元素替换为和)。
移动到下一个元素进行下一轮操作。
输出结果:
输出总和 sum。
7-3 图深度优先遍历
编写程序对给定的有向图(不一定连通)进行深度优先遍历,图中包含n个顶点,编号为0至n-1。本题限定在深度优先遍历过程中,如果同时出现多个待访问的顶点,则优先选择编号最小的一个进行访问,以顶点0为遍历起点。
输入格式:
输入第一行为两个整数n和e,分别表示图的顶点数和边数,其中n不超过20000,e不超过50。接下来e行表示每条边的信息,每行为两个整数a、b,表示该边的端点编号,但各边并非按端点编号顺序排列。
输出格式:
输出为一行整数,每个整数后一个空格,即该有向图的深度优先遍历结点序列。
输入样例1:
3 3
0 1
1 2
0 2
输出样例1:
0 1 2
输入样例2:
4 4
0 2
0 1
1 2
3 0
输出样例2:
0 1 2 3
答案
#include<bits/stdc++.h>
using namespace std;
int book[20005];
vector<int> v[20005];
void dfs(int cur) {
cout << cur << " ";
book[cur] = 1;
int len = v[cur].size();
for (int i = 0;i < len;i++) {
if (book[v[cur][i]] == 0) {
dfs(v[cur][i]);
}
}
}
int main() {
int n, e;
cin >> n >> e;
int a, b;
for (int i = 1;i <= e;i++) {
cin >> a >> b;
v[a].push_back(b);
}
for (int i = 0;i < n;i++) {
sort(v[i].begin(), v[i].end());
}
for(int i=0;i<n;i++){
if(book[i]==0)
dfs(i);
}
}
解题思路:
输入处理:
读入两个整数 n 和 e,分别表示图中节点的数量和边的数量。
使用 e 对输入的边进行处理,将边的两个端点 a 和 b 存入邻接表 v 中,表示图的连接关系。
图的表示:
使用邻接表 v 来表示图,其中 v[i] 存储了与节点 i 直接相连的所有节点。
为了保证遍历时的顺序,使用 sort 对每个节点的邻接节点进行排序。
深度优先搜索(DFS):
从未访问的节点开始,调用 dfs 函数进行深度优先搜索。
在 dfs 函数中,访问当前节点,标记为已访问,然后递归地访问所有与当前节点直接相连且未被访问的节点。
遍历完成后,返回到上一个节点。
处理所有连通组件:图可能由多个连通组件组成,因此需要在主函数中对所有节点进行检查。
如果节点未被访问,则调用 dfs 函数从该节点开始遍历,确保所有连通组件都被访问到。
7-4 快速排序
本题目要求读入N个整数,采用快速排序法进行排序,输出前3轮排序后的结果。
输入格式:
输入不超过100的正整数N和N个整数(空格分隔)。
输出格式:
输出三行,第一行为第一轮排序结果,第二行为第二轮排序结果,第三行为第三轮排序结果。数据间用一个空格分隔。
为简便起见,最后一个元素后也有一个空格。
输入样例:
7
4 3 1 5 2 7 6
输出样例:
2 3 1 4 5 7 6
1 2 3 4 5 7 6
1 2 3 4 5 7 6
答案
#include <stdio.h>
// 定义一个全局变量记录当前轮次
int currentRound = 0;
// 打印数组函数
void printArray(int arr[], int n) {
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
// 快速排序分区函数
int partition(int arr[], int low, int high) {
int pivot = arr[low];
while (low < high) {
while (low < high && arr[high] >= pivot) high--;
arr[low] = arr[high];
while (low < high && arr[low] <= pivot) low++;
arr[high] = arr[low];
}
arr[low] = pivot;
return low;
}
// 快速排序递归函数
void quickSort(int arr[], int low, int high, int n) {
if (low < high) {
int pivot = partition(arr, low, high);
currentRound++;
if (currentRound <= 3) {
printArray(arr, n);
}
quickSort(arr, low, pivot - 1, n);
quickSort(arr, pivot + 1, high, n);
}
}
int main() {
int n;
scanf("%d", &n);
int arr[n];
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}
// 初始调用快速排序函数
quickSort(arr, 0, n - 1, n);
return 0;
}
解题思路:
输入处理:
从标准输入读取数组的大小 n。
读取 n 个整数并存储到数组 arr 中。
快速排序:
分区函数 (partition): 选择第一个元素作为基准(pivot),然后通过两个指针将数组划分为小于基准的部分和大于基准的部分。
递归排序函数 (quickSort):
如果当前子数组有多于一个元素,调用 partition 函数进行分区。
根据分区结果递归地对左右两部分进行排序。
在每次递归中,检查是否是前3轮的排序过程,并打印数组状态。
输出:
打印前3轮的数组状态,以便观察排序过程中的变化。
代码分析