算法与数据结构第五次作业——排序
算法与数据结构实验题 5.12 Bubble Sort
★实验任务 给定一个 1~N 的排列P ,即1到N中的每个数在P中都出现一次。
现在要对排列P进行冒泡排序,代码如下:
for (int i = 1; i <= N; ++i)
for (int j = N, t; j > i; ‐‐j)
if (P[j ‐ 1] > P[j])
t = P[j], P[j] = P[j ‐ 1], P[j ‐ 1] = t;
在排序过程中,数字的位置可能会发生变化。对于1~N的每个数字,你需要输出过程中达到的最左位置下标和最右位置下标的差的绝对值。
80%的数据:N<=1000
100%的数据:N<=100000
输入示例
4
3 2 1 4
输出示例
2 1 2 0
Hint
样例冒泡排序过程:
swap 2 1: 3 2 1 4 > 3 1 2 4
swap 3 1: 3 1 2 4 > 1 3 2 4
swap 3 2: 1 3 2 4 > 1 2 3 4
这道题目的破题点在于如何将每个数字到达的最左侧和最右侧的位置找到。需要自己多模拟几次过程,就可以发现:每个数字到达的最右侧位置,其实就是看这个数字的右侧有几个比他小的数字,而最左侧位置就取初始位置和排序完成后的位置中较小的那一个。
考虑到数据的大小,需要采用归并的思想来解答。
- 初版代码(采用冒泡模拟的方法,数据较大的点超时)
#include<iostream>
using namespace std;
int main()
{
int n;
cin >> n;
int* a = new int[n];
int* b = new int[n];
int* min = new int[n];
int* max = new int[n];
for (int i = 0; i < n; i++)
{
cin >> a[i];
b[i] = a[i];
min[a[i] - 1] = i;
max[a[i] - 1] = i;
}
for (int i = n-1; i >= 0; i--)
{
for (int j = 0,t; j < i; j++)
{
if (a[j] > a[j+1])
{
t = a[j], a[j] = a[j + 1], a[j + 1] = t;
if (max[a[j] - 1] < j) max[a[j] - 1] = j;
if (min[a[j] - 1] > j) min[a[j] - 1] = j;
if (max[a[j + 1] - 1] < j+1) max[a[j + 1] - 1] = j+1;
if (min[a[j + 1] - 1] > j+1) min[a[j + 1] - 1] = j+1;
}
}
}
for (int i = 0; i < n; i++)
{
int pos = max[i] - min[i];
cout << pos << ' ';
}
}
- 归并做法(与归并排序类似)
#include<iostream>
#include<cstdio>
using namespace std;
int Right[100001] = { 0 };
int Left[100001] = { 0 };
int Pos[100001] = { 0 };
void merge(int a[], int left, int mid, int right)
{
int l_pos = left;
int r_pos = mid+1;
int pos = left;
int sum = 0;
for (int i = left; i <= mid; i++)
{
Left[i] = a[i];
}
for (int i = mid+1; i <= right; i++)
{
Right[i] = a[i];
}
while (l_pos <= mid && r_pos <= right)
{
if (Left[l_pos] > Right[r_pos])
{
sum++;
a[pos++] = Right[r_pos++];
}
else
{
Pos[Left[l_pos]] += sum;
a[pos++] = Left[l_pos++];
}
}
while (l_pos <= mid)
{
Pos[Left[l_pos]] += sum;
a[pos++] = Left[l_pos++];
}
while (r_pos <= right)
{
a[pos++] = Right[r_pos++];
}
}
void msort(int a[], int left, int right)
{
if (left < right)
{
int mid = (left + right) / 2;
msort(a, left, mid);
msort(a, mid + 1, right);
merge(a, left, mid, right);
}
}
int min(int a, int b)
{
if (a > b) return b;
else return a;
}
int main()
{
int a[100001]; int b[100001];
int n;
cin >> n;
for (int i = 1; i <= n; i++)
{
scanf_s("%d", &a[i]);
b[a[i]] = i;
}
msort(a, 1, n);
for (int i = 1; i <= n; i++)
{
cout << b[i] + Pos[i] - min(i, b[i])<<' ';
}
}
算法与数据结构实验题 5.18 小孩的游戏
★实验任务
一群小孩子在玩游戏,游戏规则是这样子,给了一些卡片,上面有数字,现在要把卡片按照某一种序列排好,让这些数字重新链接组合成一个大数,求最大的数是什么。
★数据输入
第一行一个整数N
接下来N行,每行一个整数ai,为第i张卡片上的数值。(0<=ai<=100)
50%数据 1<=N<=50000
100%数据1<=N<=100000
★数据输出
输出重新组合好的大数。
输入示例
3
99
23
99
输出示例
999923
采用的是桶排序的思想
#include<iostream>
using namespace std;
int main()
{
int a[101] = { 0 };
int n;
cin >> n;
int m;
for (int i = 0; i < n; i++)
{
cin >> m;
a[m]++;
}
for (int i = 9; i >= 1; i--)
{
if (a[i] != 0)
{
for (int j = 9; j >= i; j--)
{
while (a[i * 10 + j] != 0)
{
cout << i * 10 + j;
a[i * 10 + j]--;
}
}
while (a[i] != 0)
{
cout << i;
a[i]--;
}
for (int j = i - 1; j >= 0; j--)
{
while (a[i * 10 + j] != 0)
{
cout << i * 10 + j;
a[i * 10 + j]--;
}
}
}
else
{
for (int j = 9; j >= 0; j--)
{
while (a[i * 10 + j] != 0)
{
cout << i * 10 + j;
a[i * 10 + j]--;
}
}
}
}
while (a[100] != 0)
{
cout << 100;
a[100]--;
}
while (a[0] != 0)
{
cout << 0;
a[0]--;
}
}