2021数据结构与算法实验合集
Posted 一腔诗意醉了酒
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021数据结构与算法实验合集相关的知识,希望对你有一定的参考价值。
第十四周 哈希查找
A. DS哈希查找—线性探测再散列
题目描述
定义哈希函数为H(key) = key%11,输入表长(大于、等于11)。输入关键字集合,用线性探测再散列构建哈希表,并查找给定关键字。
--程序要求--
若使用C++只能include一个头文件iostream;若使用C语言只能include一个头文件stdio
程序中若include多过一个头文件,不看代码,作0分处理
不允许使用第三方对象或函数实现本题的要求
输入
测试次数t
每组测试数据为:
哈希表长m、关键字个数n
n个关键字(关键字为互不相同的正整数)
查找次数k
k个待查关键字
输出
对每组测试数据,输出以下信息:
构造的哈希表信息,数组中没有关键字的位置输出NULL
对k个待查关键字,分别输出:0或1(0—不成功,1—成功)、比较次数、查找成功的位置(从1开始)
样例输入
1
12 10
22 19 21 8 9 30 33 4 15 14
4
22
56
30
17
样例输出
22 30 33 14 4 15 NULL NULL 19 8 21 9
1 1 1
0 6
1 6 2
0 1
提示
// 问题 A: DS哈希查找—线性探测再散列
#include <iostream>
using namespace std;
#define INF -99
int main()
{
int t;
cin >> t;
while (t--)
{
int m, n;
cin >> m >> n;
int *a = new int[m];
for (int i = 0; i < m; i++)
a[i] = INF;
// 建表
while (n--)
{
int num;
cin >> num;
int di = 1;
int h = num % 11;
if (a[h] == INF)
{
a[h] = num;
continue;
}
while (true)
{
int temp = (h + di) % m;
if (a[temp] == INF)
{
a[temp] = num;
break;
}
else
{
di++;
}
}
}
for (int i = 0; i < m; i++)
{
if (a[i] == INF)
cout << "NULL"
<< " ";
else
cout << a[i] << " ";
}
cout << endl;
int k;
cin >> k;
while (k--)
{
int f;
cin >> f;
int h = f % 11;
int times = 0;
int di = 1;
int flag = 0;
int tf = 0;
int temp = h;
/**************
* 查找分三种情况:
* 1. 要找的关键字的hash地址为空
* 2. 要找的关键字的hash地址不为空且等于关键字
* 3. 要找的关键字的hash地址不为空,也不等于关键字,则进行线性探测
*
*
* **********/
if (a[h] == INF)
{ // 第一种情况
cout << 0 << " " << 1 << endl;
}
else
{
if (a[h] == f)
{ // 第二种情况
cout << 1 << " " << 1 << " " << h + 1 << endl;
continue;
}
times++;
while (true)
{ // 第三种情况
int temp = (h + di) % m;
times++;
if (a[temp] == f)
{
cout << 1 << " " << times << " " << temp + 1 << endl;
flag = 1;
break;
}
else if (a[temp] == INF)
{
break;
}
di++;
} // while
if (flag == 0)
{
cout << 0 << " " << times << endl;
}
}
}
}
return 0;
}
B. DS哈希查找—二次探测再散列(关键字互不相同)
题目描述
定义哈希函数为H(key) = key%11。输入表长(大于、等于11),输入关键字集合,用二次探测再散列构建哈希表,并查找给定关键字。
输入
测试次数t
每组测试数据格式如下:
哈希表长m、关键字个数n
n个关键字(关键字为互不相同的正整数)
查找次数k
k个待查关键字
输出
对每组测试数据,输出以下信息:
构造的哈希表信息,数组中没有关键字的位置输出NULL
对k个待查关键字,分别输出:
0或1(0—不成功,1—成功)、比较次数、查找成功的位置(从1开始)
样例输入
1
12 10
22 19 21 8 9 30 33 4 41 13
4
22
15
30
41
样例输出
22 9 13 NULL 4 41 NULL 30 19 8 21 33
1 1 1
0 3
1 3 8
1 6 6
提示
// 问题 B: DS哈希查找—二次探测再散列(关键字互不相同)
#include<iostream>
using namespace std;
#define INF -99
int main()
{
int t;
cin >> t;
while( t-- ){
int m, n;
cin >> m >> n;
int * a = new int[m+5];
for( int i=0; i<m; i++) a[i] = INF;
// 建表
while( n-- ){
int num ;
cin >> num;
int di = 1;
int h = num%11;
h %= m;
if(a[h]==INF){
a[h] = num;
continue;
}
while( true ){
int t1 = (h+di*di)%m;
int t2 = (h-di*di)%m;
while(t1>=m){
t1-=m;
}
while(t2<0){
t2+=m;
}
/*******
* 重点: 这里一定要注意对t2的取值范围进行处理,小于0的时候要进行循环移位
* 博主在初学这个的时候,可是被他坑惨了呜呜
*
* ******/
if( a[t1%m] == INF ){
a[t1] = num;
break;
} else if( a[t2%m] == INF ){
a[t2] = num;
break;
}
else{
di++;
}
}
}
for(int i=0; i<m; i++){
if(a[i] == INF ) cout<<"NULL"<<" ";
else cout<<a[i]<<" ";
}
cout << endl;
int k;
cin >> k;
while(k--) {
int f;
cin >> f;
int h = f%11;
int times = 0;
int flag = 0; // 没找到为0, 找到为1
int tf = 0;
int di = 1;
/**************
* 查找分三种情况:
* 1. 要找的关键字的hash地址为空
* 2. 要找的关键字的hash地址不为空且等于关键字
* 3. 要找的关键字的hash地址不为空,也不等于关键字,则进行二次探测(平方)
*
* #### 注意比较次数自加的位置 (在进行比较之前进行次数+1)
* 1. 先和自身的hash地址比较
* 2. 和t1 = (h+di*di)%m; t1的地址比较
* 3. 和t2 = (h-di*di)%m; t2 的地址比较
* **********/
if(a[h]==INF){ // 第一种情况
cout<<0<<" "<<1<<endl;
}
else{
times ++;
if( a[h]==f ){ // 第二种情况
cout<< 1 << " " << times << " " << h+1 <<endl;
continue;
}
while(true){ // 第三种情况
int t1 = (h+di*di)%m;
int t2 = (h-di*di)%m;
while(t1>=m){
t1-=m;
}
while(t2<0){
t2+=m;
}
times++;
if( a[t1%m]==f ){
cout<<1<<" "<<times<<" "<<t1+1<<endl;
flag = 1;
break;
}
if(a[t1%m]==INF ){ // 遇到NULL就跳出
break;
}
times++;
if( a[t2%m]==f ){
cout<<1<<" "<<times<<" "<<t2+1<<endl;
flag = 1;
break;
}
if( a[t2%m]==INF ){ // 遇到NULL就跳出
break;
}
di ++;
if(di>m/2) {
break;
};
}
if( flag==0 ){
cout<<0<<" "<<times<<endl;
}
}
}
}
return 0;
}
关于表长的一个小tips
-
- 可以通过设置表长=
4k+3
,来获取完全剩余系,规避重复搜索 - 如果表长不是
4k+3
, 冲突次数达到一定的阈值,就需要重新建表
- 可以通过设置表长=
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ayxIdZYA-1623337233975)(C:\\Users\\dcs\\Desktop\\notes\\study\\MD\\03数据结构与算法\\pics\\image-20210610153428027.png)]
C. DS哈希查找–链地址法
题目描述
给出一个数据序列,建立哈希表,采用求余法作为哈希函数,模数为11,哈希冲突用链地址法和表头插入
如果首次查找失败,就把数据插入到相应的位置中
实现哈希查找功能
输入
多组数据,每组数据:
第一行输入n,表示有n个数据
第二行输入n个数据,都是自然数且互不相同,数据之间用空格隔开
第三行输入t,表示要查找t个数据
从第四行起,每行输入一个要查找的数据,都是正整数
输出
每行输出对应数据的查找结果
样例输入
6
11 23 39 48 75 62
6
39
52
52
63
63
52
样例输出
6 1
error
8 1
error
8 1
8 2
提示
注意,当两次输入要相同的查找数据,如果第一次查找不成功就会执行插入,那么第二次查找必然成功,且查找次数为1次(因为做表头插入)
例如示例数据中输入两次52,第一次查找失败就把52插入到位置8,第二次查找就成功了,所以第一次输出error,第二次就输出8 1
为什么第三次输入52会输出8 2
需要考虑有多轮数据输入的情况!也就是第一个cin或者scanf需要用while来进行循环,例如 while(cin>>...)
#include<iostream>
using namespace std;
const int is = 11;
int a[is][99];
void move(int k){
for(int i=a[k][0]; i>0; i--){
a[k][i+1] = a[k][i];
}
}
void insert(int data){
int k = data%is;
a[k][0] += 1;
// 采用头插法 ,所以要移动数据
move(k);
a[k][ 1 ] = data;
}
void search(int data){
int k = data%is;
int flag = 0;
for(int j=1, len = a[k][0]; j<=len; j++ ){
if(a[k][j]==data){
cout<<k<<" "<<j<<endl;
flag = 1;
break;
}
}
if(flag==0){
cout<<"error"<<endl;
insert(data);
}
}
int main(){
int t;
while(cin >> t){
for(int i=0; i<is; i++){
a[i][0] = 0; // 0位记录当前表项的数据元素
for(int j=1; j<99; j++){
a[i][j] = -1;
}
}
while(t--){
int temp;
cin>>temp;
insert(temp);
}
int steps;
cin >> steps;
while(steps--){
/****************
* 要搜索的值情况分三种:
* 1. 要搜索的值的记录表没有记录
* 2. 要搜索的值的记录表有记录,但没有要找的值
* 3. 要搜索的值的记录表有记录,但有要找的值
****************/
int find;
cin >> find;
int k = find%is;
if( a[k][0] == 0){
cout<<"error"<<endl;
insert(find);
}
else{
search(find);
}
}
}
return 0;
}
D. 问题 D: DS哈希查找与增补
题目描述
给出一个数据序列,建立哈希表,采用求余法作为哈希函数,模数为11,哈希冲突用链地址法和表尾插入
如果首次查找失败,就把数据插入到相应的位置中
实现哈希查找与增补功能
输入
第一行输入n,表示有n个数据
第二行输入n个数据,都是自然数且互不相同,数据之间用空格隔开
第三行输入t,表示要查找t个数据
从第四行起,每行输入一个要查找的数据,都是正整数
输出
每行输出对应数据的查找结果,每个结果表示为数据所在位置[0,11)和查找次数,中间用空格分开
样例输入
6
11 23 39 48 75 62
6
39
52
52
63
63
52
样例输出
6 1
error
8 1
error
8 2
8 1
提示
#include<iostream>
using namespace std;
const int is = 11;
int a[is][99];
void insert(int data){
int k = data%is;
a[k][0] += 1;
a[k][ a[k][0] ] = data;
}
void search(int data){
int k = data%is;
int flag = 0;
for(int j=1, len = a[k][0]; j<=len; j++ ){
if(a[k][j]==data){
cout<<k<<" "<<j<<endl;
flag = 1;
break;
}
}
if(flag==0){
cout<<"error"<<endl;
insert(data);
}
}
int main(){
int t;
while(cin >> t){
for(int i=0; i<is; i++){
a[i][0] = 0; // 0位记录当前表项的数据元素
for(int j=1; j<99; j++){
a[i][j] = -1;
}
}
while(t--){
int temp;
cin>>temp;
insert(temp);
}
int steps;
cin >> steps;
while(steps--){
/****************
* 要搜索的值情况分三种:
* 1. 要搜索的值的记录表没有记录
* 2. 要搜索的值的记录表有记录,但没有要找的值
* 3. 要搜索的值的记录表有记录,但有要找的值
****************/
int find;
cin >> find;
int k = find%is;
if( a[k][0] == 0){
cout<<"error"<<endl;
insert(find);
}
else{
search(find);
}
}
}
return 0;
}
第十五周 DS排序
A. DS排序–直接插入排序
题目描述
给出一个数据序列,使用直接插入排序算法进行降序排序。
输入
第一行输入t,表示有t个测试示例
第二行输入n,表示第一个示例有n个数据(n>1)
第三行输入n个数据,都是正整数,数据之间用空格隔开
以此类推
输出
对每组测试数据,输出每趟排序结果。不同组测试数据间用空行分隔。
样例输入
2
5
111 22 6 444 333
6
21 25 49 25 16 8
样例输出
111 22 6 444 333
111 22 6 444 333
444 111 22 6 333
444 333 111 22 6
25 21 49 25 16 8
49 25 21 25 16 8
49 25 25 21 16 8
49 25 25 21 16 8
49 25 25 21 16 8
提示
#include<iostream>
using namespace std;
void show(int a[], int len){
for(int i=0; i<len; i++){
cout<<a[i]<<" ";
}
cout<<endl;
};
void z_sort(int a[], int len){
for(int i=1; i<len; i++){
for(int j=i; (j>0) && ( a[j]>a[j-1]) ; j-- ){
a[j] ^= a[j-1];
a[j-1] ^= a[j];
a[j] ^= a[j-1];
}
show(a, len);
}
}
int main(){
int step;
cin >> step;
while(step--){
int t;
cin >> t;
int *a = new int[t+5];
for(int i=0; i<t; i++) cin>>a[i];
z_sort(a, t);
cout<<endl;
}
return 0;
}
B.DS排序–折半插入排序
题目描述
给出一个数据序列,使用折半插入排序算法进行降序排序。
输入
第一行输入t,表示有t个测试示例
第二行输入n,表示第一个示例有n个数据(n>1)
第三行输入n个数据,都是正整数,数据之间用空格隔开
以此类推
输出
对每组测试数据,输出每趟排序结果。不同组测试数据间用空行分隔。
样例输入
2
5
111 22 6 444 333
8
30 13 70 85 39 42 6 20
样例输出
111 22 6 444 333
111 22 6 444 333
444 111 22 6 333
444 333 111 22 6
30 13 70 85 39 42 6 20
70 30 13 85 39 42 6 20
85 70 30 13 39 42 6 20
85 70 39 30 13 42 6 20
85 70 42 39 30 13 6 20
85 70 42 39 30 13 6 20
85 70 42 39 30 20 13 6
提示
#include<iostream>
using namespace std;
void show(int a[], int len){
for(int i=0; i<len; i++){
cout<<a[i]<<" ";
}
cout<<endl;
};
void z_sort(int a[], int len){
int low = 0,high = 0,mid;
int temp = 0;
for (int i=1; i<len; i++) {
low=0;
high=i-1;
temp=a[i];
while (low<=high) {
mid=(low+high)/2;
if (a[mid]<temp) {
high=mid-1;
}else{
low=mid+1;
}
}
for (int j=i; j>low; j--) {
a[j]=a[j-1];
}
a[low]=temp;//插入元素
show(a, len);
}
}
int main(){
int step;
cin >> step;
while(step--){
int t;
cin >> t;
int *a = new int[t+5];
for(int i=0; i<t; i++) cin>>a[i];
z_sort(a, t);
cout<<endl;
}
return 0;
}
c. DS排序–希尔排序
题目描述
给出一个数据序列,使用希尔排序算法进行降序排序。
间隔gap使用序列长度循环除2直到1
输入
第一行输入t,表示有t个测试示例
第二行输入n,表示第一个示例有n个数据(n>1)
第三行输入n个数据,都是正整数,数据之间用空格隔开
以此类推
输出
对每组测试数据,输出每趟排序结果。不同组测试数据间用空行分隔。
样例输入
2
6
111 22 6 444 333 55
8
77 555 33 1 444 77 666 2222
样例输出
444 333 55 111 22 6
444 333 111 55 22 6
444 555 666 2222 77 77 33 1
666 2222 444 555 77 77 33 1
2222 666 555 444 77 77 33 1
提示
#include<iostream>
using namespace std;
void show(int a[], int len){
for(int i=0; i<len; i++){
cout<<a[i]<<" ";
}
cout<<endl;
};
void Shell(int a[], int len){
for( int gap = len/2; gap >= 1; gap/=2 ){
for(int i = 0; i<gap; i++){
for (int j = i + gap; j < len; j += gap)
if (a[j] > a[j - gap])
{
int temp = a[j];
int k = j - gap;
while (k >= 0 && a[k] < temp)
{
a[k + gap] = a[k];
k -= gap;
}
a[k + gap] = temp;
}
}
show(a,len);
}
}
int main()
{
int step;
cin >> step;
while(step--){
int t;
cin >> t;
int *a = new int[t+5];
for(int i=0; i<t; i++) cin>>a[i];
Shell(a, t);
cout<<endl;
delete []a;
}
return 0;
}
D. DS排序–冒泡排序
题目描述
给定一个包含从0到n-1各一次的数组,若使用冒泡排序将其排为升序,问其中需要进行多少次交换
输入
测试数据有多组,
每组由两行组成:第一行包含正整数n(n <= 5000); 下一行包含从0到n-1的n个整数的序列。
输出
对于每组测试数据,
输出交换次数
样例输入
10
1 3 6 9 0 8 5 7 4 2
样例输出
22
提示
需要考虑有多轮数据输入的情况!也就是第一个cin或者scanf需要用while来进行循环,例如 while(cin>>...)
#include<iostream>
using namespace std;
void show(int a[], int len){
for(int i=0; i<len; i++){
cout<<a[i]<<" ";
}
cout<<endl;
}
int main(){
int t;
while( cin>>t){
int a[t+5];
int ans = 0;
for(int i=0; i<t; i++) cin>>a[i];
for(int i=0; i<t-1; i++){
for(int j=i+1; j<t; j++){
if(a[i]>a[j]){
int temp = a[i];
a[i] = a[j];
a[j] = temp;
ans++;
}
// show(a,t);
}
}
cout<<ans<<endl;
}
return 0;
}
E. DS排序–快速排序
题目描述
给出一个数据序列,使用快速排序算法进行从小到大的排序
排序方式:以区间第一个数字为枢轴记录
输出方式:每一步区间排序,都输出整个数组
--程序要求--
若使用C++只能include一个头文件iostream;若使用C语言只能include一个头文件stdio
程序中若include多过一个头文件,不看代码,作0分处理
不允许使用第三方对象或函数实现本题的要求
输入
第一行输入t,表示有t个测试示例
第二行输入n,表示第一个示例有n个数据
第三行输入n个数据,都是正整数,数据之间用空格隔开
以此类推
输出
每组测试数据,输出每趟快排的结果,即每次排好一个数字结果(长度为1的子序列,不用排,不用输出)。不同测试数据间用空行分隔。
样例输入
2
6
111 22 6 444 333 55
8
77 555 33 1 444 77 666 2222
样例输出
55 22 6 111 333 444
6 22 55 111 333 444
6 22 55 111 333 444
6 22 55 111 333 444
1 33 77 555 444 77 666 2222
1 33 77 555 444 77 666 2222
1 33 77 77 444 555 666 2222
1 33 77 77 444 555 666 2222
1 33 77 77 444 555 666 2222
提示
#include<iostream>
using namespace std;
int length;
void show(int *a){
for(int i=0; i<length; i++){
cout<<a[i]<<" ";
}
cout<<endl;
};
void q_sort(int a[], int left, int right){
// left, right 左闭右开, low、high闭区间
if(left >= right-1 ) return;
int low = left, high = right-1, center = a[low];
while( low < high ){
while( low<high && a[high] >= center ) high --;
a[low] = a[high];
while( low< high && a[low] <= center) low++;
a[high] = a[low];
}
a[low] = center;
show(a);
q_sort(a, left, low);
q_sort(a, low+1, right );
}
int main(){
int step;
cin>>step;
while(step--){
int t;
cin >> t;
int *a = new int[t+5];
length = t;
for(int i=0; i<t; i++) cin>>a[i];
q_sort( a, 0, t);
cout<<endl;
}
return 0;
}
以上是关于2021数据结构与算法实验合集的主要内容,如果未能解决你的问题,请参考以下文章