Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
23
Добавлен:
03.03.2016
Размер:
2.87 Mб
Скачать

2. Вывод одномерного массива на экран.

Для компактности изображения массива на экране в каждой строке экрана целесообразно печатать несколько элементов массива.

Пусть формат вывода элемента вещественного массива имеет вид 8:2. Устанавливая между числами два пробела, в одной строке экрана можно разместить 8 чисел (строка экрана содержит 80 позиций). Тогда программа вывода может иметь вид:

.....................

k=0;

for (i=0;i<n;i++)

{

k++;

if (k<8)

printf("%8.2lf ",x[i]);

else

{

k=0;

printf("%8.2lf\n",x[i]);

}

}

if (k>0) printf("\n");

.....................

Переменная k - это счетчик количества чисел, выводимых в одну строку экрана. Пока k < 8, функция printf("%8.2lf ",x[i]) размещает очередные элементы массива в одной и той же строке экрана через 2 пробела. При k = 8 после вывода числа производится переход на следующую строку экрана printf("%8.2lf\n",x[i]), при этом счетчику k присваивается нулевое значение.

Предположим, что в массиве X количество элементов не кратно 8. Тогда вывод последнего элемента будет осуществлен без перехода на новую строку экрана. Если в программе после вывода массива X выполняется еще вывод хотя бы одного числа, то это число будет размещено в той же строке экрана, где расположен элемент , что по крайней мере неэстетично. Для предотвращения такой ситуации в вышеприведенной программе записан оператор "if (k>0) printf("\n");".

Если известно, что печатаемые значения будут занимать менее, например, 8 символов, то можно воспользоваться оператором:

for(i=0; i<n;i++) printf("%8.2lf",x[i]);

без использования счетчика выведенных значений. В этом случае, в строке распечатается 10 значений, разделенных, по меньшей мере, одним пробелом, после чего курсор автоматически будет переведен на следующую строку. Этот способ уменьшает сложность программы печати значений массива и применим в тех случаях, когда можно в формате печати задать длину поля числом, на которое 80 будет делиться без остатка.

Примеры обработки одномерных массивов

Пример 1. Вычислить среднее арифметическое значение элементов массива X=(x0, x1, x2, …, xn-1).

Блок-схема

Си-программа

#define NMAX 500

int main()

{

int i, // параметр цикла

n; // кол-во элементов массива

float S; // среднее арифметическое значение

float X[NMAX]; // исходный массив

//Ввод и печать n, X

S=0;

for (i=0;i<n;i++)

S += X[i];

S /= n;

//Печать S

getch();

return 0;

}

В программе переменная S используется, как сумматор. Поэтому в программе перед накоплением в переменной S суммы элементов массива X производится обнуление этой переменной оператором S = 0. Вместо этого оператора можно было использовать инициализацию переменной при ее определении, если до использования в цикле ее значение не изменялось.

Следует обратить внимание еще на одно обстоятельство. Массиву Х в программе выделяется память, необходимая для размещения 500 элементов. В принципе в программе можно было бы написать: for (i=0;i<NMAX;i++).

Однако это означало бы, что программа может обрабатывать лишь массив, содержащий 500 элементов, но не 499 или 100. Поэтому для обеспечения универсальности работы программы обработке подвергается текущее количество элементов n в предположении, что 0<n<NMAX.

Пример 2. Вычислить среднее арифметическое значение положительных элементов массива X=(x0, x1, x2, …, xn-1).

Блок-схема

Отличие решения этой задачи от предыдущего примера заключается в том, что перед накоплением сумы элементов массива в S проверяется его значение (оно должно быть положительным X[i] > 0). В переменной k подсчитывается количество таких чисел. В частном случае в массиве X может не быть ни одного положительного элемента (k==0). Тогда при отсутствии оператора «if (k>0)» было бы деление на нуль, что даст неправильный результат. В программе используется оператор «if (k)», т.к. значение k может быть только нулевым или больше нуля.

Си-программа

#define NMAX 500

int main()

{

int i, // параметр цикла

k, // счетчик положительных чисел

n=10;// кол-во элементов массива

float S; // среднее арифметическое значение

float x[NMAX]; // исходный массив

//Ввод и печать n, X

S=k=0;

for (i=0;i<n;i++)

if (x[i]>0)

{

S+=x[i]; k++;

}

if (k)

S/=k;

//Печать S

getch();

return 0;

}

Пример 3. Определить y=max(x0, x1, x2, …, xn-1).

Первый элемент массива принимается за максимальный и записывается в переменную max. Далее в цикле осуществляется просмотр массива, и каждый i-й элемент сравнивается со значением max. Если i-й элемент массива больше max, то запоминается новое значение максимального элемента.

Си программа

#define NMAX 500

int main()

{

int i, // параметр цикла

n; // кол-во элементов массива

float max; // максимальное значение

float x[NMAX]; // исходный массив

//Ввод и печать n, X

max=x[0];

for (i=1;i<n;i++)

if (x[i]>max)

max=x[i];

//Печать max

getch();

return 0;

}

Пример 4. Определить y=max(x0, x1, x2, …, xn-1) среди отрицательных элементов массива.

Применить алгоритм из примера 2 нельзя. Если первый элемент массива принимать за максимальный, а он может быть положительным или нулем, то в этом случае ни одно из отрицательных чисел не будет больше него. Поэтому в переменную Xmax записывается неотрицательное значение, например, 0. Это так называемый «флаг». Далее в цикле осуществляется просмотр массива, начиная с нулевого, и каждый i-й элемент проверяется на соответствие требованиям к элементам, включаемым в поиск максимума (отрицательные). Если i-й элемент массива отрицательный, то проверяется значение флага. Если Xmax==0 (значение, которое в него было записано до начала цикла), считается, что это появление первого отрицательного элемента, его сравнивать еще не с чем, он просто запоминается. Таким образом, в Xmax появляется ненулевое значение – признак того, что отрицательные числа были, и очередной отрицательный элемент массива есть с чем сравнивать. Говорят, что значение флага изменилось. В качестве флага можно использовать отдельную переменную. В нашем случае Xmax является флагом и одновременно в ней запоминается значение максимума.

Если Xmax!=0, то x[i] сравнивается со значением Xmax. Если i-й элемент массива больше Xmax, то запоминается новое значение максимального элемента.

Си программа

#define NMAX 500

int main()

{

int i, // параметр цикла

n; // кол-во элементов массива

float Xmax; // максимальное значение

float x[NMAX]; // исходный массив

//Ввод и печать n, X

Xmax=0;

for (i=0;i<n;i++)

if (x[i]<0)

if (Xmax==0)

Xmax=x[i];

else

if (x[i]>Xmax)

Xmax=x[i];

//Печать max

getch();

return 0;

}

Пример 5. Обменять местами максимальный и минимальный элементы массива X.

Здесь требуется найти не только значения переменных Xmax и Xmin, но и положение (индексы) соответствующих им элементов в массиве X (значения переменных imax и imin).

Вариант 1.

#define NMAX 500

int main()

{

int i, // параметр цикла

n, // кол-во элементов массива

imax,imin; // позиции max и min элементов

float Xmax,Xmin; // максимальное и минимальное значение

float x[NMAX]; // исходный массив

//Ввод и печать n, X

Xmax=x[0]; Xmin=x[0];

imax=0; imin=0;

for (i=1;i<n;i++)

{

if (x[i]>Xmax)

{

Xmax=x[i]; imax=i;

}

if (x[i]<Xmin)

{

Xmin=x[i]; imin=i;

}

}

x[imax]=Xmin; x[imin]=Xmax;

//Печать x

getch();

return 0;

}

В каждом цикле элемент сравнивается со значениями переменных Xmax и Xmin. В то же время очевидно, что если выполняется условие > Xmax, то проверка отношения < Xmin является излишней. Указанное замечание учтено в варианте 2.

Вариант 2 (фрагмент).

for (i=1;i<n;i++)

{

if (x[i]>Xmax)

{

Xmax=x[i]; imax=i;

}

else

if (x[i]<Xmin)

{

Xmin=x[i]; imin=i;

}

}

При обмене значений элементов x[imax] и x[imin] использовано то обстоятельство, что после окончания обработки массива известны не только значения индексов imax и imin, но и численные значения переменных Xmax и Xmin. Обмен в данном случае осуществляется по такой схеме:

Примечание. Было бы совершенно неправильно выполнять обмен максимального и минимального элементов массива X операторами

R = Xmax; Xmax = Xmin; Xmin = R;

(R - переменная типа float), так как здесь обмениваются значения переменных Xmax и Xmin, а не значения элементов массива X с индексами imax и imin.

Пример 6. В массиве X найти значение и положение первого отрицательного элемента.

Решение рассматриваемой задачи выполнено в двух вариантах.

Вариант 1.

#define NMAX 500

int main()

{

int i, // параметр цикла

n, // кол-во элементов массива

ineg=-1; // положение первого отрицательного элемента

float Xneg; // значение первого отрицательного элемента

float x[NMAX]; // исходный массив

//Ввод и печать n, X

i=0;

while(i<n && x[i] >= 0)

i++;

if(i==n)

printf("\nОтрицательных элементов нет\n");

else

{

ineg=i; Xneg=x[i];

//Печать ineg, Xneg

}

getch();

return 0;

}

В программе последовательно просматриваются элементы массива X и, как только обнаруживается отрицательный элемент или заканчивается просмотр массива, цикл прерывается. Если в массиве X нет ни одного отрицательного элемента (признаком будет выполнение условия i==n), в программе будет отпечатано соответствующее сообщение.

Если i<n, значит цикл был прерван по нарушению условия x[i] >= 0. Отрицательный элемент найден, в переменных Xneg, ineg запоминаются значение и индекс этого элемента, после чего они распечатываются.

Вариант 2 (фрагмент).

//Ввод и печать n, X

for(i=0; i<n && x[i]>=0;i++);

if(i==n)

printf("\nОтрицательных элементов нет\n");

else

{

ineg=i; Xneg=x[i];

//Печать ineg, Xneg

}

Вместо цикла while можно использовать цикл for .

В таком применении цикл for не использует тело цикла. Алгоритм реализуется в заголовке цикла.

Пример 7. В массиве X определить местоположение последнего положительного элемента.

Вариант 1.

#define NMAX 500

int main()

{

int i, // параметр цикла

n, // кол-во элементов массива

ipos=-1;// положение последнего положительного элемента

float x[NMAX]; // исходный массив

//Ввод и печать n, X

i=0;

while( i < n )

if (x[i] > 0) ipos=i;

if(ipos==-1)

printf("\nПоложительных элементов нет\n");

else

//Печать ipos, X[ipos]

getch();

return 0;

}

Переменная ipos используется двояко:

- для запоминания позиции найденного положительного элемента. Так как просматривается весь массив, то в переменной запишется позиция последнего найденного положительного элемента. Это и будет искомый элемент;

- как флаг. Если по окончании цикла в ней будет значение -1, значит, не было найдено ни одного положительного элемента.

В программе просматриваются все элементы массива X, что нерационально с точки зрения затрат машинного времени. Более эффективной является программа варианта 2, в которой просмотр массива X осуществляется справа налево до обнаружения ближайшего положительного элемента.

Вариант 2 (фрагмент).

//Ввод и печать n, X

for(i=n-1; i>=0 && x[i]<=0;i--);

if(i==-1)

printf("\nПоложительных элементов нет\n");

else

{

ipos=i;

//Печать ipos, X[ipos]

}

Пример 8. Дано целое десятичное число А. Сформировать массив двоичных цифр числа. Выполнить сложение с 1. Из массива цифр сформировать преобразованное число А1.

Введенное десятичное число необходимо проверить на диапазон допустимых значений:

1. А должно быть неотрицательным. Отрицательные числа представляются в дополнительном коде, а, значит, необходимо по другому алгоритму формировать массив двоичных цифр и иначе учесть это при добавлении 1.

2. А не должно быть равно максимальному числу, записанному в формате int, в противном случае добавление 1 вызовет переполнение разрядной сетки, результат будет неверным. Для проверки можно использовать предопределенную константу INT_MAX - максимальной целое положительное число в формате int.

Для формирования массива двоичных цифр используется алгоритм получения двоичных цифр числа. Первой выделяется цифра младшего 0-го разряда, затем 1-го и т.д. Цифры записываются в массив b[i++]=a1%2 – сначала в i-й элемент массива запишется двоичная цифра, после чего переменная i увеличится на 1.

Выполнение сложения двух двоичных чисел a и b выполняется поразрядно: si=ai+bi+pi-1. В нем участвуют текущие разряды чисел и перенос из младшего разряда. В нашем случае числа b нет. Для прибавления единицы в младший разряд перед началом цикла перенос из несуществующего младшего разряда устанавливается в 1. Вычисления проводятся по формуле ai=ai+pi-1.

Сумма в текущем разряде может принимать значения 0, 1, 2. Цифры 2 в 2-ой системе счисления нет, поэтому устанавливается перенос в старший разряд, а в текущий разряд записывается 0. При значении суммы 0 или 1 – перенос в старший разряд равен 0 – цикл можно прерывать.

Десятичное число формируется из массива двоичных цифр по схеме Горнера.

int main()

{

int a,a1,digit,i,n,buf,p;

char b[32];

//Ввод и контроль a>0

a1=a;//Для сохранения исходных данных

i=0;

do //Цикл формирования массива двоичных цифр целого числа

{

b[i++]=a1%2;

a1=a1/2;

}

while(a1 != 0);

n=i;//n - размер массива b и одновременно количество цифр в двоичном числе

//Выполним сложение с 1.

p=1; i=0;

while(i<n && p==1)

{b[i]=b[i]+p;

if(b[i]==2)

b[i]=0; //Перенос был - значение p не изменяется

else

p=0; //Переноса не было - p устанавливается в 0

i++;

}

// если был перенос из старшего разряда, то добавляется 1 разряд и в него записывается 1

if(p==1)

{b[n]=1;n++;}

//В поле a1 сформируем преобразованное число по схеме Горнера

a1=0;

for(i=n-1; i>=0; i--)

a1=a1*2+b[i];

//Печать а1

getch();

return 0;

}

Формировать число можно и с использованием весовых коэффициентов. Но такой способ требует больших затрат времени на его выполнение

a1=0; p=1;

for(i=0; i<n; i++)

{ a1+=b[i]*p; p*=2; }

Пример 9. Расположить элементы массива в обратном порядке.

При выполнении заданного преобразования нужно произвести обмен значений элементов и , и , и и так далее до достижения "середины" массива .

Вариант 1.

#define NMAX 1000

int main()

{

double x[NMAX];

int n,i,R;

//Ввод n и массива x

for (i=0;i<n/2;i++)

{

R=x[i]; x[i]=x[n-1-i]; x[n-1-i]=R;

}

//Печать массива x

getch();

return 0;

}

Вариант 2 (фрагмент).

i=0; j=n-1;

while (i<j)

{

R=x[i]; x[i]=x[j]; x[j]=R;

i++; j--;

}

Вариант 3 (фрагмент).

for (i=0,j=n-1; i<j; i++,j--)

{

R=x[i]; x[i]=x[j]; x[j]=R;

}

Все три варианта примера 9 равнозначны с точки зрения эффективности вычислений, но варианты 2 и 3 более наглядны. Они более удобны также в случае, когда требуется выполнить перестановку не всего массива, а подмассива, например, с номера n1 до номера n2. Тогда записываются операторы i=n1 и j=n2, остальная часть программы не изменяется.

В третьем варианте применяется операция последовательного вычисления «запятая». Так как в выражениях заголовка цикла for может стоять только один оператор, а есть необходимость использовать в данном примере 2 оператора, это реализуется операцией «запятая». Таким образом, в заголовке цикла for можно инициализировать и изменять любое количество переменных.

Пример 10. Дано целое десятичное число А. Определить, сколько раз каждая десятичная цифра встречается в числе А.

Наиболее эффективный способ решения этой задачи заключается в использовании массива счетчиков. Определяется массив из десяти целочисленных элементов (десяти счетчиков). Индексы элементов изменяются от 0 до 9. Каждый элемент соответствует своей цифре. При выделении очередной цифры, к соответствующему счетчику прибавляется 1. Выделенная цифра является индексом при обращении к массиву. Например, если очередная выделенная цифра равна 4, то 4-й элемент массива наращивается на 1. Таким образом, наиболее просто определить, какая цифра сколько раз встречается в заданном числе.

int main()

{ int a,a1,digit,i,n;

char c_dig[10]={0,0,0,0,0,0,0,0,0,0};//Массив счетчиков цифр

//Ввод а

a1=abs(a);

i=0;

do //Цикл формирования массива цифр целого десятичного числа

{

digit=a1%10;

a1=a1/10;

c_dig[digit]++;

}

while(a1 != 0);

//Печать результата из массива счетчиков

printf("\nВхождение десятичных цифр в А\n");

for(i=0; i<10; i++)

printf("Цифра %d входит %d раз \n",i,c_dig[i]);

getch();

return 0;

}

Перед началом цикла формирования массива цифр все его элементы необходимо обнулить. Если массив формируется однократно, его можно проинициализировать при определении, как показано в примере. Если эта операция будет производиться неоднократно, то обнуление массива необходимо выполнять каждый раз перед запуском цикла формирования массива цифр оператором:

for(i=0; i<10; i++) c_dig[i]=0;

Соседние файлы в папке Прогр_обменка