ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 23.06.2021

Просмотров: 1684

Скачиваний: 3

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
background image

36 

При асинхронной обработке массивов индекс каждого массива меняется по 

своей схеме. 

Пример 2.  В массиве целых чисел все отрицательные элементы перенести в 

начало массива. 

int b[10];//вспомогательный массив 

int i,j=0; 

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

if(a[i]<0){b[j]=a[i];j++;}//переписываем из а в b все отрицательные 

элементы 

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

if(a[i]>=0){b[j]=a[i];j++;}// переписываем из а в b все 

положительные элементы 

for(i=0;i<n;i++) cout<<b[I]<<” “; 

Пример3. 
Удалить из массива все четные числа 
int b[10]; 
 

int i,j=0; 

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

if(a[i]%2!=0){b[j]=a[i];j++;} 

for(i=0;i<j;i++) cout<<b[i]<<" "; 

cout<<"\n";  

6.3.4. Задачи 4-ого класса 

 
В поисковых задачах требуется найти элемент, удовлетворяющий заданному 

условию. Для этого требуется организовать перебор массива и проверку условия. Но 
при этом существует две возможности выхода из цикла: 

-

нужный элемент найден ; 

-

элемент не найден, но просмотр массива закончен. 

Пример1. Найти первое вхождение элемента К в массив целых чисел. 
 

int k; 

cout<<"\nK=?";cin>>k; 

int ok=0;//признак найден элемент или нет 

int i,nom; 

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

if(a[i]==k){ok=1;nom=i;break;} 

if(ok==1) 

cout<<"\nnom="<<nom; 

else 

cout<<"\nthere is no such element!";  

6.4. Сортировка массивов 

 
Сортировка – это процесс перегруппировки заданного множества объектов в 

некотором установленном порядке.  

Сортировки массивов подразделяются по быстродействию. Существуют 

простые методы сортировок, которые требуют n*n сравнений, где n – количество 
элементов массива и быстрые сортировки, которые требуют n*ln(n) сравнений. 
Простые методы удобны для объяснения принципов сортировок, т. к. имеют простые и 


background image

37 

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

Простые методы подразделяются на три основные категории: 
-

сортировка методом простого включения; 

-

сортировка методом простого выделения; 

-

сортировка методом простого обмена; 

6.4.1. Сортировка методом простого включения (вставки) 

 
Элементы массива делятся на уже готовую последовательность и исходную. При 

каждом шаге, начиная с I=2, из исходной последовательности извлекается I-ый элемент 
и вставляется на нужное место готовой последовательности, затем I увеличивается на 1 
и т. д.  
44 

55  12  42  94  18 

готовая 

исходная 

 
В процессе поиска нужного места осуществляются пересылки элементов больше 

выбранного на одну позицию вправо, т. е. выбранный элемент сравнивают с очередным 
элементом отсортированной части, начиная с J:=I-1. Если выбранный элемент больше 
a[I], то его включают в отсортированную часть, в противном случае a[J] сдвигают на 
одну позицию, а выбранный элемент сравнивают со следующим элементом 
отсортированной последовательности. Процесс поиска подходящего места 
заканчивается при двух различных условиях:  

-

если найден элемент a[J]>a[I]; 

-

достигнут левый конец готовой последовательности. 

 
 

int i,j,x; 

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

x=a[i];//запомнили элемент, который будем вставлять 
 

j=i-1; 

while(x<a[j]&&j>=0)//поиск подходящего места 

a[j+1]=a[j];//сдвиг вправо 

j--; 


 

a[j+1]=x;//вставка элемента 

6.4.2. Сортировка методом простого выбора 

 
Выбирается минимальный элемент массива и меняется местами с первым 

элементом массива. Затем процесс повторяется с оставшимися элементами и т. д. 

4

5

1

4

9

1

м

ин 

 
 

int i,min,n_min,j; 


background image

38 

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

min=a[i];n_min=i;//поиск минимального 

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

if(a[j]<min){min=a[j];n_min=j;} 

a[n_min]=a[i];//обмен 

a[i]=min; 

6.4.3. Сортировка методом простого обмена 

Сравниваются и меняются местами пары элементов, начиная с последнего. В 

результате самый маленький элемент массива оказывается самым левым элементом 
массива. Процесс повторяется с оставшимися элементами массива. 

4

5

1

4

9

1

 
for(int i=1;i<n;i++) 
for(int j=n-1;j>=i;j--) 
if(a[j]<a[j-1]) 
{int r=a[j];a[j]=a[j-1];a[j-1]=r;} 
}  
 

6.5. Поиск в отсортированном массиве 

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

При последовательном поиске требуется в среднем n/2 сравнений, где n – количество 
элементов в массиве. При дихотомическом поиске требуется не более m сравнений, 
если n- m-ая степень 2, если n не является степенью 2, то n<k=2

m

Массив делится пополам S:=(L+R)/ 2+1 и определяется в какой части 

массива находится нужный элемент Х. Т .к. массив упорядочен, то если a[S]<X, то 
искомый элемент находится в правой части массива, иначе -  находится в левой части. 
Выбранную часть массива снова надо разделить пополам и т. д., до тех пор, пока 
границы отрезка L и R не станут равны.  

1  3  8  1

1

1

1

2

2

3

0  1  2  3 

L                       S                                   R 
S=(L+R)/2=4 
 
 

int b; 

cout<<"\nB=?";cin>>b; 

int l=0,r=n-1,s; 

do 

s=(l+r)/2;//средний элемент 

if(a[s]<b)l=s+1;//перенести леую границу 
else r=s;//перенести правую границу 

}while(l!=r); 

if(a[l]==b)return l; 

else return -1; 


background image

39 

7.  Указатели

7.1. Понятие указателя 

Указатели  являются  специальными  объектами  в  программах  на  Си++.  

Указатели предназначены для хранения адресов памяти.  

Пример:  Когда  компилятор  обрабатывает  оператор  определения  переменной, 

например,  int  i=10;,  то  в  памяти  выделяется  участок  памяти  в  соответствии  с  типом 
переменной  (int=>  4байта)  и  записывает  в  этот  участок  указанное  значение.  Все 
обращения к этой переменной компилятор заменит на адрес области памяти, в которой 
хранится эта переменная.  

 
а 
 
 
Программист может определить собственные переменные для хранения адресов 

областей  памяти.  Такие  переменные  называются  указателями.  Указатель  не  является 
самостоятельным типом, он всегда связан с каким-то другим типом.  

Указатели  делятся  на  две  категории:  указатели  на  объекты  и  указатели  на 

функции.  Рассмотрим  указатели  на  объекты,  которые  хранят  адрес  области  памяти, 
содержащей данные определенного типа . 

В простейшем случае объявление указателя имеет вид: 
тип *имя; 
Тип может быть любым, кроме ссылки. 
Примеры: 
int *i; 
double *f, *ff; 
char *c; 
Размер  указателя  зависит  от  модели  памяти.  Можно  определить  указатель  на 

указатель: int**a; 

Указатель  может  быть  константой  или  переменной,  а  также  указывать  на 

константу или переменную. 

Примеры: 
1. int i;  

//целая переменная  

const int ci=1; //целая константа 
int *pi;  

//указатель на целую переменную 

const int *pci;//указатель на целую константу 
Указатель можно сразу проинициализировать: 
int *pi=&i;  

//указатель на целую переменную 

const int *pci=&ci;;//указатель на целую константу 

2. 

int*const cpi=&i;//указатель-константа на целую переменную 

const int* const cpc=&ci;//указатель-константа на целую константу 
Если  модификатор  const  относится  к  указателю  (т.  е.  находится  между  именем 

указателя и * ), то он запрещает изменение указателя, а если он находится слева от типа 
(т. е. слева от * ), то он запрещает изменение значения, на которое указывает указатель. 

Для инициализации указателя существуют следующие способы: 

1)

Присваивание адреса существующего объекта: 

1) с помощью операции получения адреса  
int a=5; 
int *p=&a; или int p(&a); 
2) с помощью проинициализированного указателя 
int *r=p; 

10 

&a 

           a 
 
*p 
 
  
          *r          &a 


background image

40 

3) адрес присваивается в явном виде 
char*cp=(char*)0х В800 0000; 
где 0х В800 0000 – шестнадцатеричная константа, (char*) – операция приведения 

типа. 

4) присваивание пустого значения: 
int*N=NULL; 
int *R=0; 
 

7.2. Динамические переменные 

Все переменные, объявленные в программе размещаются в одной непрерывной 

области  памяти,  которую  называют  сегментом  данных  (64К).  Такие  переменные  не 
меняют  своего  размера  в  ходе  выполнения  программы  и  называются  статическими. 
Размера сегмента данных может быть недостаточно для размещения больших массивов 
информации. Выходом из этой ситуации является использование динамической памяти. 
Динамическая  память  –  это  память,  выделяемая  программе  для  ее  работы  за  вычетом 
сегмента данных, стека, в котором размещаются локальные переменные подпрограмм и 
собственно тела программы. 

Для  работы  с  динамической  памятью  используют  указатели.  С  их  помощью 

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

Для  создания  динамических  переменных  используют  операцию  new, 

определенную в СИ++: 

указатель = new имя_типа[инициализатор]; 
где инициализатор – выражение в круглых скобках. 
Операция new позволяет выделить и сделать доступным участок динамической 

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

int*x=new int(5); 
Для  удаления  динамических  переменных  используется  операция  delete, 

определенная в СИ++: 

delete указатель; 
где  указатель  содержит  адрес  участка  памяти,  ранее  выделенный  с  помощью 

операции new. 

delete x; 
В  языке  Си  определены  библиотечные  функции  для  работы  с  динамической 

памятью, они находятся в библиотеке <stdlib.h>: 

1)

void*malloc(unsigned  s)  –  возвращает  указатель  на  начало  области  динамической 
памяти длиной s байт, при неудачном завершении возвращает NULL; 

2)

void*calloc(unsigned  n,  unsigned  m)  –  возвращает  указатель  на  начало  области 
динамической  для  размещения  n  элементов  длиной  m  байт  каждый,  при  неудачном 
завершении возвращает NULL; 

3)

void*realloc(void  *p,unsigned  s)  –изменяет  размер  блока  ранее  выделенной 
динамической до размера  s байт, р – адрес начала изменяемого блока, при неудачном 
завершении возвращает NULL; 

4)

void *free(void *p) – освобождает ранее выделенный участок динамической памяти, р- 
адрес начала участка. 

Пример: