#ifndef ARRAYINT_H
#define ARRAYINT_H
#include
class ArrayInt
{
private:
int m_length;
int *m_data;
public:
ArrayInt():
m_length(0), m_data(nullptr)
{
m_length=0;
m_data=nullptr;
}
ArrayInt(int length):
m_length(length)
{
assert(length >= 0);
if (length > 0)
m_data = new int[length];
else
m_data = nullptr;
}
~ArrayInt()
{
delete[] m_data;
}
void erase()
{
delete[] m_data;
// Chiqishda osilgan ko'rsatgich bo'lmasligi uchun m_data ni nullptr ga o'rnating
m_data = nullptr;
m_length = 0;
}
int& operator[](int index)
{
assert(index >= 0 && index < m_length);
return m_data[index];
}
int getLength() { return m_length; }
};
#endif
Endi biz foydalanishimiz mumkin bo'lgan ArrayInt sinfiga egamiz. Biz ma'lum o'lchamdagi massivni ajratishimiz va elementlarning qiymatlarini olish yoki o'zgartirish uchun [] operatoridan foydalanishimiz mumkin.
Biroq, ArrayInt bilan biz qila olmaydigan yana bir nechta narsa bor. Bular massivning avtomatik oʻlchamini oʻzgartirish, elementlarni qoʻshish/oʻchirish va elementlarni saralash.
Birinchidan, massivni o'lchamini o'zgartirish mumkin bo'lsin. Buning uchun ikki xil funksiya yozamiz. Birinchi funktsiya qayta reallocate(), massiv hajmi o'zgartirilganda, u barcha mavjud elementlarni yo'q qiladi (bu tez). Ikkinchi funktsiya resize(), massiv o'lchamini o'zgartirganda, u barcha mavjud elementlarni saqlab qoladi (bu sekin).
// reallocate () funksiyasi massiv hajmini o'zgartiradi.
//Massiv ichidagi barcha mavjud elementlar yo'q qilinadi.
//Jarayon tez
void reallocate(int newLength)
{
// Massiv ichidagi barcha mavjud elementlarni olib tashlash
erase();
// Agar massivimiz bo'sh bo'lishi kerak bo'lsa, biz bu yerga qaytamiz
if (newLength <= 0)
return;
// Keyin biz yangi elementlarni tanlashimiz kerak
m_data = new int[newLength];
m_length = newLength;
}
// resize() funksiyasi massiv hajmini o'zgartiradi. Barcha mavjud elementlar saqlanib qoladi. Jarayon sekin
void resize(int newLength)
{
// Agar massiv kerakli uzunlikka ega bo'lsa, return bajaring
if (newLength == m_length)
return;
// Agar massivni bo'sh qilish kerak bo'lsa, buni bajaring va keyin return ni bajaring
if (newLength <= 0)
{
erase();
return;
}
// Endi, deylik newLength kamida bitta elementga ega. Quyidagi harakatlar ketma-ketligi amalga oshiriladi:
// 1. Yangi massivni ajrating.
// 2. Mavjud massivdagi elementlarni yangi tanlangan massivimizga nusxalash.
// 3. Eski massivni yo'q qiling va yangi massivga ishora qilish uchun m_data buyrug'ini bering.
int *data = new int[newLength];
// Keyin yangi massivga nusxalanadigan elementlar sonini aniqlashimiz kerak.
// Massivlarning kichikroq qismidagi qancha elementlar bo'lsa, shuncha ko'p elementni nusxalashimiz kerak
if (m_length > 0)
{
int elementsToCopy = (newLength > m_length) ? m_length : newLength;
// Elementlarni birma-bir nusxalash
for (int index=0; index < elementsToCopy ; ++index)
data[index] = m_data[index];
}
// Eski massivni o'chirib tashlang, chunki bizga endi kerak emas
delete[] m_data;
// Va eskisini o'rniga yangisini ishlating! E'tibor bering, m_data bizning yangi dinamik ravishda ajratilgan massivimiz ko'rsatgan manzilga ishora qiladi.
// Ma'lumotlar dinamik ravishda ajratilganligi sababli, ular ko'lamdan chiqib ketganda yo'q qilinmaydi
m_data = data;
m_length = newLength;
}
Ko’rib turganingizdek bu oson jarayon emas. Ko'pgina konteyner massivi sinflarining funksionalligi shu erda tugaydi. Ammo, agar siz elementlarni qo'shish / o'chirish qobiliyatini qanday amalga oshirishni ko'rishni istasangiz, endi biz buni ko'rib chiqamiz. Quyidagi ikkita algoritm resize() funksiyasiga juda o'xshash:
void insertBefore(int value, int index)
{
// O'tkazilgan indeksning to'g'riligini tekshirish
assert(index >= 0 && index <= m_length);
// Eski massivdan bir element kattaroq yangi massiv yarating
int *data = new int[m_length+1];
// Barcha elementlarni indeksgacha nusxalash
for (int before=0; before < index; ++before)
data[before] = m_data[before];
// Bizning yangi elementimizni yangi massivimizga joylashtiring
data [index] = value;
// Kiritilgan elementdan keyin barcha qiymatlarni nusxalash
for (int after=index; after < m_length; ++after)
data[after+1] = m_data[after];
// Eski massivni o'chiring va uning o'rniga yangi massivdan foydalaning
delete[] m_data;
m_data = data;
++m_length;
}
void remove(int index)
{
// O'tkazilgan indeksning to'g'riligini tekshiring
assert(index >= 0 && index < m_length);
// Agar bu massivning oxirgi elementi bo'lsa, u holda massivni bo'sh qilamiz va return
if (m_length == 1)
{
erase();
return;
}
// Eski massivimizdan bir element kichikroq yangi massiv yarating
int *data = new int[m_length-1];
// Barcha elementlarni indeksgacha nusxalash
for (int before=0; before < index; ++before)
data[before] = m_data[before];
// O'chirilgan elementdan keyin barcha qiymatlarni nusxalash
for (int after=index+1; after < m_length; ++after )
data[after-1] = m_data[after];
// Eski massivni o'chiring va uning o'rniga yangi massivdan foydalaning
delete[] m_data;
m_data = data;
--m_length;
}
// Qulaylik uchun bir nechta qo'shimcha funktsiyalar
void insertAtBeginning(int value) { insertBefore(value, 0); }
void insertAtEnd(int value) { insertBefore(value, m_length); }
Mana bizning ArrayInt konteyner sinfimiz.
ArrayInt.h:
#ifndef ARRAYINT_H
#define ARRAYINT_H
#include // для assert()
class ArrayInt
{
private:
int m_length;
int *m_data;
public:
ArrayInt():
m_length(0), m_data(nullptr)
{
}
ArrayInt(int length):
m_length(length)
{
assert(length >= 0);
if (length > 0)
m_data = new int[length];
else
m_data = nullptr;
}
~ArrayInt()
{
delete[] m_data;
}
void erase()
{
delete[] m_data;
// Здесь нужно указать m_data значение nullptr, чтобы на выходе не было висячего указателя
m_data = nullptr;
m_length = 0;
}
int& operator[](int index)
{
assert(index >= 0 && index < m_length);
return m_data[index];
}
// Функция reallocate() изменяет размер массива. Все существующие элементы внутри массива будут уничтожены. Процесс быстрый
void reallocate(int newLength)
{
// Удаляем все существующие элементы внутри массива
erase();
// Если наш массив должен быть пустым, то выполняем возврат здесь
if (newLength <= 0)
return;
// Затем выделяем новые элементы
m_data = new int[newLength];
m_length = newLength;
}
// Функция resize() изменяет размер массива. Все существующие элементы сохраняются. Процесс медленный
void resize(int newLength)
{
// Если массив нужной длины, то выполняем return
if (newLength == m_length)
return;
// Если нужно сделать массив пустым, то делаем это и затем выполняем return
if (newLength <= 0)
{
erase();
return;
}
// Теперь предположим, что newLength состоит, по крайней мере, из одного элемента. Выполняется следующий алгоритм действий:
// 1. Выделяем новый массив.
// 2. Копируем элементы из существующего массива в наш только что выделенный массив.
// 3. Уничтожаем старый массив и даем команду m_data указывать на новый массив.
// Выделяем новый массив
int *data = new int[newLength];
// Затем нам нужно разобраться с количеством копируемых элементов в новый массив.
// Нам нужно скопировать столько элементов, сколько их есть в меньшем из массивов
if (m_length > 0)
{
int elementsToCopy = (newLength > m_length) ? m_length : newLength;
// Поочередно копируем элементы
for (int index=0; index < elementsToCopy ; ++index)
data[index] = m_data[index];
}
// Удаляем старый массив, так как он нам уже не нужен
delete[] m_data;
// И используем вместо старого массива новый! Обратите внимание, m_data указывает на тот же адрес, на который указывает наш новый динамически выделенный массив.
// Поскольку данные были динамически выделены, то они не будут уничтожены, когда выйдут из области видимости
m_data = data;
m_length = newLength;
}
void insertBefore(int value, int index)
{
// Проверка корректности передаваемого индекса
assert(index >= 0 && index <= m_length);
// Создаем новый массив на один элемент больше старого массива
int *data = new int[m_length+1];
// Копируем все элементы аж до index
for (int before=0; before < index; ++before)
data [before] = m_data[before];
// Вставляем наш новый элемент в наш новый массив
data [index] = value;
// Копируем все значения после вставляемого элемента
for (int after=index; after < m_length; ++after)
data[after+1] = m_data[after];
// Удаляем старый массив и используем вместо него новый массив
delete[] m_data;
m_data = data;
++m_length;
}
void remove(int index)
{
// Проверка на корректность передаваемого индекса
assert(index >= 0 && index < m_length);
// Если это последний элемент массива, то делаем массив пустым и выполняем return
if (m_length == 1)
{
erase();
return;
}
// Cоздаем новый массив на один элемент меньше нашего старого массива
int *data = new int[m_length-1];
// Копируем все элементы аж до index
for (int before=0; before < index; ++before)
data[before] = m_data[before];
// Копируем все значения после удаляемого элемента
for (int after=index+1; after < m_length; ++after )
data[after-1] = m_data[after];
// Удаляем старый массив и используем вместо него новый массив
delete[] m_data;
m_data = data;
--m_length;
}
// Несколько дополнительных функций просто для удобства
void insertAtBeginning(int value) { insertBefore(value, 0); }
void insertAtEnd(int value) { insertBefore(value, m_length); }
int getLength() { return m_length; }
};
#endif
Edi dasturni testdan o’tkazamiz
#include
#include "ArrayInt.h"
int main()
{
// Объявляем массив с 10 элементами
ArrayInt array(10);
// Заполняем массив числами от 1 до 10
for (int i=0; i<10; i++)
array[i] = i+1;
// Изменяем размер массива до 7 элементов
array.resize(7);
// Вставляем число 15 перед элементом с индексом 4
array.insertBefore(15, 4);
// Удаляем элемент с индексом 5
array.remove(5);
// Добавляем числа 35 и 50 в конец и в начало
array.insertAtEnd(35);
array.insertAtBeginning(50);
// Выводим все элементы массива
for (int j=0; jstd::cout << array[j] << " ";
return 0;
}
Natija:
50 1 2 3 4 15 6 7 35
Konteyner sinflarini yozish biroz qiyin bo'lishi mumkin bo'lsa-da, yaxshi xabar shundaki, ularni faqat bir marta yozishingiz kerak. Konteyner klassi ishga tushirilgandan so'ng, uni istalgan joyda qo'shimcha kodlash/kodlash harakatlarisiz qayta ishlatishingiz mumkin.
Shuni ham ta'kidlash joizki, ArrayInt konteyner sinfimiz asosiy ma'lumotlar turini (int) o'z ichiga olsa ham, biz maxsus ma'lumotlar turidan ham osonlikcha foydalanishimiz mumkin.
Eslatma: Agar C ++ standart kutubxonasi sinfi sizning ehtiyojlaringizga to'liq javob bersa, o'z konteyner sinfingizni yozish o'rniga undan foydalaning. Masalan, ArrayInt o'rniga std :: vektor dan foydalanish yaxshidir, chunki std :: vektor ilovasi ko'p yillar davomida sinovdan o'tgan/tasdiqlangan, samarali va C sinfidagi boshqa sinflar bilan yaxshi ishlaydi. ++ Standart kutubxona. Ammo C ++ standart kutubxonasidan sinflardan foydalanish har doim ham imkoni bo'lmasligi mumkinligi sababli, siz o'zingizning konteyner sinflaringizni qanday yaratishni allaqachon bilasiz.
24-25-MA’RUZA. STANDART SHABLONLAR SINFIGA KIRISH (KOLLEKSIYALAR SINFI),ASOSIY TUSHUNCHALAR. KONTEYNER SINFLAR TIPLARI, KONTEYNERLAR ADAPTERLARI. ALGORITMLAR VA ULARNI KONTEYNER SINFLAR BILAN ISHLATISH USULLARI
Do'stlaringiz bilan baham: |