Опубликован: 07.03.2015 | Уровень: для всех | Доступ: свободно | ВУЗ: Компания ALT Linux
Лекция 5:

Массивы

Задача 5.9. Удалить из массива все отрицательные элементы, расположенные между максимальным и минимальным элементами массива X[n].

Решение этой задачи можно разделить на следующие этапы:

  1. Ввод массива.
  2. Поиск номеров максимального (nmax) и минимального (nmin) элементов массива.
  3. Определение меньшего (a) и большего (b) из чисел nmax и nmin.
  4. Далее, необходимо перебрать все элементы массива, расположенные между числами с номерами a и b. Если число окажется отрицательным, то его необходимо удалить. Однако на этом этапе нужно учитывать тонкий момент. Если просто организовать цикл от a+1 до b-1, то при удалении элемента изменяется количество элементов, расположенных между a и b, и номер последнего удаляемого элемента. Это может привести к тому, что не всегда корректно будут удаляться отрицательные элементы, расположенные между a и b. Поэтому этот цикл для удаления организован несколько иначе.

Текст программы:

#include <iostream>
#include <math.h>
using namespace std;
int main ( int argc, char **argv )
{
	int i, j, k, n, nmax, nmin, *x, a, b;
	cout<<" n = "; cin>>n; //Ввод количества элементов в массиве.
	x=new int [ n ]; //Выделяем память для динамического массива x.
	cout<<"Введите элементы массива X \n "; //Ввод элементов массива.
	for ( i =0; i<n; i++)
		cin>>x [ i ];
	//Поиск номеров максимального и минимального элементов в массиве.
	for (nmax=nmin= i =0; i<n; i++)
	{
		if ( x [ i ]<x [ nmin ] ) nmin= i;
		if ( x [ i ]>x [ nmax ] ) nmax= i;
	}
	//Проверяем, что раньше расположено, минимум или максимум
	if ( nmin<nmax )
	{
		a=nmin;
		b=nmax;
	}
	else
	{
		a=nmax;
		b=nmin;
	}
	//Перебираем все элементы, расположенные между максимумом и минимумом
	for ( i=a+1,k=1;k<=b-a-1;k++)
		if ( x [ i ] <0) //Проверяем, является ли очередной элемент массива отрицательным.
			{//Если текущий элемент массива является отрицательным числом, удаляем его
			for ( j= i; j<n-1; j++)
				x [ j ]=x [ j + 1 ];
			n--;
		}
		else i ++; //Если x[i]>=0, переходим к следующему элементу.
	cout<<"Преобразованный массив X\n ";
	for ( i =0; i<n; i++)
		cout<<x [ i ]<<" \t ";
	cout<<endl;
	return 0;
}

В качестве тестового можно использовать следующий массив: 34, 4, -7, -8, -10, 7, -100, -200, -300, 1. Здесь приведённая выше программа работает корректно, а вариант

for ( i=a+1; i<b; )
	if ( x [ i ] <0)
	{
		for ( j= i; j<n-1; j++)
			x [ j ]=x [ j + 1 ];
		n--;
	}
	else i ++;

приводит к неправильным результатам. Рекомендуем читателю самостоятельно разобраться в особенностях подобных алгоритмов удаления.

Задача 5.10. В массиве X[n] найти группу наибольшей длины, которая состоит из знакочередующихся чисел.

Если будут вычислены следующие значения:

  • nach — номер первого элемента в группе;
  • kon — номер последнего элемента в группе;
  • k — количество элементов в группе.

то, зная любые два из них, можно однозначно определить группу внутри массива.

Вначале количество элементов в знакочередующейся группе равно 1. Дело в том, что если мы встретим первую пару знакочередующихся элементов, то количество их в группе сразу станет равным 2. Однако все последующие пары элементов будут увеличивать k на 1. И чтобы не решать проблему построения последовательности значений k 0,2,3,4,5,..., первоначальное значение k примем равным 1. Когда будем встречать очередную пару подряд идущих соседних элементов, то k необходимо будет увеличить на 1.

Алгоритм поиска очередной группы состоит в следующем: попарно (x_i, x_{i+1}) перебираем все элементы массива (параметр цикла i изменяется от 0 до n - 2).

Если произведение соседних элементов отрицательно (xi \cdot x_i+1 < 0), то это означает, что они имеют разные знаки и являются элементами группы. В этом случае количество (k) элементов в группе увеличиваем на 1 (k++). Если же произведение соседних элементов положительно (x_i\cdot x_{i+1} > 0), то эти элементы не являются членами группы. В этом случае возможны два варианта:

  1. Если k > 1, то только что закончилась группа, в этом случае kon=i -номер последнего элемента в группе, k — количество элементов в только что закончившейся группе.
  2. Если k = 1, то это просто очередная пара незнакочередующихся элементов.

После того, как закончилась очередная группа знакочередующихся элементов, необходимо количество групп (kgr) увеличить на 1 (kgr++). Если это первая группа (kgr=1) знакочередующихся элементов, то в переменную max записываем длину этой группы (max=k)3В переменной, а в переменную kon_max номер последнего элемента группы (kon_max=i). Если это не первая группа (kgr=1), то сравниваем max и длину текущей группы (k). Если k>max, то в переменную max записываем длину этой группы (max=k), а в переменную kon_max номер последнего элемента группы (kon_max=i).

После этого в переменную k опять записываем 1 для формирования новой группы элементов.

По окончанию цикла значение k может быть больше 1. Это означает, что в самом конце массива встретилась ещё одна группа. Для неё надо будет провести все те же действия, что и для любой другой группы. Далее приведён текст программы.

#include <iostream>
using namespace std;
int main ( int argc, char **argv )
{ float *x;
	int i, k, n, max, kgr, kon_max;
	cout<<" n = "; cin>>n; //Ввод размера массива.
	x=new float [ n ]; //Выделение памяти для массива.
	cout<<"Введите массив x\n "; //Ввод элементов массива.
	for ( i =0; i<n; i++)
		cin>>x [ i ];
	//Попарно перебираем элементы массива. Количество знакочередующихся
	//групп в массиве kgr=0, количество элементов в текущей группе — 1.
	for ( kgr= i =0,k=1; i<n-1; i++)
		//Если соседние элементы имеют разные знаки, то количество (k)
		//элементов в группе увеличиваем на 1.
		if ( x [ i ] * x [ i +1]<0) k++;
		else
			if ( k>1) //Если k>1, то только что закончилась группа, i — номер последнего элемента
			{//в группе, k — количество элементов в группе. Увеличиваем kgr на 1.
				kgr++;
				if ( kgr==1) //Если это первая группа (kgr=1) знакочередующихся элементов,
				{
					max=k; //то max — длина группы (max=k),
					kon_max= i; //kon_max — номер последнего элемента группы.
				}
				else //это не первая группа (kgr 6= 1), сравниваем max и длину текущей группы.
					if ( k>max) //Если k>max,
					{
						max=k; //max — длина группы,
						kon_max= i; //kon_max — номер последнего элемента группы.
					}
				k=1; //В переменную k записываем 1 для формирования новой группы элементов.
			}
		if ( k>1) //Если в конце массива была группа.
		{
			kgr++; //Количество групп увеличиваем на 1.
			if ( kgr==1) //Если это первая группа,
			{
				max=k; //то max — длина группы,
				kon_max=n-1; //группа закончилась на последнем элементе массива.
			}
			else
				if ( k>max) //Если длина очередной группы больше max.
				{
					max=k; //то в max записываем длину последней группы,
					kon_max=n-1; //группа закончилась на последнем элементе массива.
				}
		}
		if ( kgr >0) //Если знакочередующиеся группы были,
		{ //то выводим информацию о группе наибольшей длины,
			cout<<"В массиве "<<kgr<<" групп знакочередующихся элементов\n ";
			cout<<"Группа максимальной длины начинается с элемента Номер
				"<<kon_max-max+1<<", её длина "<<max<<",номер последнего элемента группы
				" <<kon_max<<endl;
			for ( i=kon_max-max+1; i<=kon_max; i++) //а также саму группу.
				cout<<x [ i ]<<" ";
			cout<<endl;
		}
		else //Если знакочередующихся групп не было, то выводим сообщение об этом.
			cout<<"В массиве нет групп знакочередующихся элементов\n ";
		return 0;
}
Сергей Радыгин
Сергей Радыгин

Символы кириллицы выводит некорректно. Как сделать чтобы выводился читабельный текст на русском языке?

Тип приложения - не Qt,

Qt Creator 4.5.0 основан на Qt 5.10.0. Win7.

 

Юрий Герко
Юрий Герко

Кому удалось собрать пример из раздела 13.2 Компоновка (Layouts)? Если создавать проект по изложенному алгоритму, автоматически не создается  файл mainwindow.cpp. Если создавать этот файл вручную и добавлять в проект, сборка не получается - компилятор сообщает об отсутствии класса MainWindow. Как правильно выполнить пример?