题目描述:以不多于3n/2的平均比较次数,在一个有n个整数的顺序表中找到最大值和最小值。要求使用的空间尽可能的少。(C++实现)
从本篇文章开始,我们使用C++来实现数据结构的相关问题,本题即是C++数据结构的一个基本问题,首先我们来实现一个顺序表,使用类定义:
class SeqList
{
private:
int* data; //元素
int size; //链表大小
public:
//构造函数
SeqList(int n) :size(n) {
data = new int[size]; //根据输入大小动态分配内存
}
SeqList() {
delete[] data; //释放内存
}
void Input() { //输入顺序表中元素
std::cout << "请输入" << size << "个整数" << std::endl;
for (int i = 0; i < size; i++) {
std::cin >> data[i];
}
}
int Get(int index) const { //索引顺序表中某一元素
if (index >= 0 && index < size) {
return data[index];
}
else std::cout << "错误索引" << std::endl;
return 1;
}
};
由于题目设计的框架比较简单,所以这里我们的顺序表只需要实现一个输入元素和一个索引元素的
方法,这里只涉及C++中的一些基本输入输出。
然后就是在表中找出最大值最小值的算法,最简单最容易想到的,即是一次历边,对每个元素,比较它与当前最大、最小值的大小,然后进行修改。(list是创建的顺序表)
int max, min;
max = min = list.Get(0);
for (int i = 1; i < n; i++) {
if (list.Get(i) > max) {
max = list.Get(i);
}
if (list.Get(i) < min) {
min = list.Get(i);
}
}
这样的程序简单,但是对每个元素进行了两次比较,使得程序的平均比较次数达到了2(n-1),超出了题目的要求!
这里我们换一种方法,两两比较法。这一方法的原理是将顺序表中的元素两两分组,然后一起与当前的最大、最小值进行比较,我们直接看代码:
if (n % 2 == 1){ //先根据元素总数奇偶性决定max、min的初始值
max = min = list.Get(0); //为奇数,直接赋为首元素1
}
else{ //为偶数,先比较前两个元素,决出最大最小值
if (list.Get(0) > list.Get(1)) {
max = list.Get(0);
min = list.Get(1);
}
else {
min = list.Get(0);
max = list.Get(1);
}
}
for (int i = (n % 2 == 0) ? 2 : 1; i < n; i += 2) {
//每两个为一组,先决出组内的最大最小值,再与当前的最大最小值比较
if (list.Get(i) > list.Get(i + 1)) {
if (list.Get(i) > max) {
max = list.Get(i);
}
if (list.Get(i + 1) < min) {
min = list.Get(i + 1);
}
}
else {
if (list.Get(i) < min) {
min = list.Get(i);
}
if (list.Get(i + 1) > max) {
max = list.Get(i + 1);
}
}
}
由此,每两个元素进行了三次比较,那么n个整数的顺序表总共比较了3n/2次满足了题目要求。
以下是完整代码:
#include<iostream>
using namespace std;
class SeqList
{
private:
int* data; //元素
int size; //链表大小
public:
//构造函数
SeqList(int n) :size(n) {
data = new int[size]; //根据输入大小动态分配内存
}
SeqList() {
delete[] data; //释放内存
}
void Input() { //输入顺序表中元素
std::cout << "请输入" << size << "个整数" << std::endl;
for (int i = 0; i < size; i++) {
std::cin >> data[i];
}
}
int Get(int index) const { //索引顺序表中某一元素
if (index >= 0 && index < size) {
return data[index];
}
else std::cout << "错误索引" << std::endl;
return 1;
}
};
int main() {
int n;
std::cout << "输入顺序表的大小:";
std::cin >> n;
SeqList list(n);
list.Input();
int max, min;
/*max = min = list.Get(0);
for (int i = 1; i < n; i++) {
if (list.Get(i) > max) {
max = list.Get(i);
}
if (list.Get(i) < min) {
min = list.Get(i);
}
}*/
//每两个元素为一组进行比较
if (n % 2 == 1){ //先根据元素总数奇偶性决定max、min的初始值
max = min = list.Get(0); //为奇数,直接赋为首元素1
}
else{ //为偶数,先比较前两个元素,决出最大最小值
if (list.Get(0) > list.Get(1)) {
max = list.Get(0);
min = list.Get(1);
}
else {
min = list.Get(0);
max = list.Get(1);
}
}
for (int i = (n % 2 == 0) ? 2 : 1; i < n; i += 2) {
//每两个为一组,先决出组内的最大最小值,再与当前的最大最小值比较
if (list.Get(i) > list.Get(i + 1)) {
if (list.Get(i) > max) {
max = list.Get(i);
}
if (list.Get(i + 1) < min) {
min = list.Get(i + 1);
}
}
else {
if (list.Get(i) < min) {
min = list.Get(i);
}
if (list.Get(i + 1) > max) {
max = list.Get(i + 1);
}
}
}
//每两个元素共比较3次,平均比较次数为3n/2
std::cout << "最大值:" << max << endl << "最小值:" << min << std::endl;
return 0;
}