Этот обработчик для сработает, если вы кликните по любому из вложенных тегов, будь то или :
Если вы кликните на EM, сработает обработчик на DIV
Вам не кажется это странным? Почему же сработал обработчик на , если клик произошёл на ?
Всплытие
Принцип всплытия очень простой.
Когда на элементе происходит событие, обработчики сначала срабатывают на нём, потом на его родителе, затем выше и так далее, вверх по цепочке предков.
Например, есть 3 вложенных элемента FORM > DIV > P с обработчиком на каждом:
body *
Клик по внутреннему
вызовет обработчик onclick :
Сначала на самом
.
Потом на внешнем .
Затем на внешнем .
И так далее вверх по цепочке до самого document .
Поэтому если кликнуть на
, то мы увидим три оповещения: p → div → form .
Этот процесс называется «всплытием», потому что события «всплывают» от внутреннего элемента вверх через родителей подобно тому, как всплывает пузырёк воздуха в воде.
Почти все события всплывают.
Ключевое слово в этой фразе – «почти».
Например, событие focus не всплывает. В дальнейшем мы увидим и другие примеры. Однако, стоит понимать, что это скорее исключение, чем правило, всё-таки большинство событий всплывают.
event.target
Всегда можно узнать, на каком конкретно элементе произошло событие.
Самый глубокий элемент, который вызывает событие, называется целевым элементом, и он доступен через event.target .
Отличия от this (= event.currentTarget ):
event.target – это «целевой» элемент, на котором произошло событие, в процессе всплытия он неизменен.
this – это «текущий» элемент, до которого дошло всплытие, на нём сейчас выполняется обработчик.
Например, если стоит только один обработчик form.onclick , то он «поймает» все клики внутри формы. Где бы ни был клик внутри – он всплывёт до элемента , на котором сработает обработчик.
При этом внутри обработчика form.onclick :
this (= event.currentTarget ) всегда будет элемент , так как обработчик сработал на ней.
event.target будет содержать ссылку на конкретный элемент внутри формы, на котором произошёл клик.
example.css
form.onclick = function(event) < event.target.style.backgroundColor = 'yellow'; // браузеру нужно некоторое время, чтобы зарисовать всё жёлтым setTimeout(() =>< alert("target = " + event.target.tagName + ", this=" + this.tagName); event.target.style.backgroundColor = '' >, 0); >;
Клик покажет оба: и event.target, и this для сравнения:
Возможна и ситуация, когда event.target и this – один и тот же элемент, например, если клик был непосредственно на самом элементе , а не на его подэлементе.
Прекращение всплытия
Всплытие идёт с «целевого» элемента прямо наверх. По умолчанию событие будет всплывать до элемента , а затем до объекта document , а иногда даже до window , вызывая все обработчики на своём пути.
Но любой промежуточный обработчик может решить, что событие полностью обработано, и остановить всплытие.
Для этого нужно вызвать метод event.stopPropagation() .
Например, здесь при клике на кнопку обработчик body.onclick не сработает:
event.stopImmediatePropagation()
Если у элемента есть несколько обработчиков на одно событие, то даже при прекращении всплытия все они будут выполнены.
То есть, event.stopPropagation() препятствует продвижению события дальше, но на текущем элементе все обработчики будут вызваны.
Для того, чтобы полностью остановить обработку, существует метод event.stopImmediatePropagation() . Он не только предотвращает всплытие, но и останавливает обработку событий на текущем элементе.
Не прекращайте всплытие без необходимости!
Всплытие – это удобно. Не прекращайте его без явной нужды, очевидной и архитектурно прозрачной.
Зачастую прекращение всплытия через event.stopPropagation() имеет свои подводные камни, которые со временем могут стать проблемами.
Мы делаем вложенное меню. Каждое подменю обрабатывает клики на своих элементах и делает для них stopPropagation , чтобы не срабатывало внешнее меню.
Позже мы решили отслеживать все клики в окне для какой-то своей функциональности, к примеру, для статистики – где вообще у нас кликают люди. Некоторые системы аналитики так делают. Обычно используют document.addEventListener(‘click’…) , чтобы отлавливать все клики.
Наша аналитика не будет работать над областью, где клики прекращаются stopPropagation . Увы, получилась «мёртвая зона».
Зачастую нет никакой необходимости прекращать всплытие. Задача, которая, казалось бы, требует этого, может быть решена иначе. Например, с помощью создания своего уникального события, о том, как это делать, мы поговорим позже. Также мы можем записывать какую-то служебную информацию в объект event в одном обработчике, а читать в другом, таким образом мы можем сообщить обработчикам на родительских элементах информацию о том, что событие уже было как-то обработано.
Погружение
Существует ещё одна фаза из жизненного цикла события – «погружение» (иногда её называют «перехват»). Она очень редко используется в реальном коде, однако тоже может быть полезной.
Стандарт DOM Events описывает 3 фазы прохода события:
Фаза погружения (capturing phase) – событие сначала идёт сверху вниз.
Фаза цели (target phase) – событие достигло целевого(исходного) элемента.
Фаза всплытия (bubbling stage) – событие начинает всплывать.
Ранее мы говорили только о всплытии, потому что другие стадии, как правило, не используются и проходят незаметно для нас.
Обработчики, добавленные через on -свойство или через HTML-атрибуты, или через addEventListener(event, handler) с двумя аргументами, ничего не знают о фазе погружения, а работают только на 2-ой и 3-ей фазах.
Чтобы поймать событие на стадии погружения, нужно использовать третий аргумент capture вот так:
elem.addEventListener(. ) // или просто "true", как сокращение для elem.addEventListener(. true)
Существуют два варианта значений опции capture :
Если аргумент false (по умолчанию), то событие будет поймано при всплытии.
Если аргумент true , то событие будет перехвачено при погружении.
Обратите внимание, что хоть и формально существует 3 фазы, 2-ую фазу («фазу цели»: событие достигло элемента) нельзя обработать отдельно, при её достижении вызываются все обработчики: и на всплытие, и на погружение.
Давайте посмотрим и всплытие и погружение в действии:
body *
Здесь обработчики навешиваются на каждый элемент в документе, чтобы увидеть в каком порядке они вызываются по мере прохода события.
Если вы кликните по
, то последовательность следующая:
HTML → BODY → FORM → DIV (фаза погружения, первый обработчик)
P (фаза цели, срабатывают обработчики, установленные и на погружение и на всплытие, так что выведется два раза)
DIV → FORM → BODY → HTML (фаза всплытия, второй обработчик)
Существует свойство event.eventPhase , содержащее номер фазы, на которой событие было поймано. Но оно используется редко, мы обычно и так знаем об этом в обработчике.
Чтобы убрать обработчик removeEventListener , нужна та же фаза
Если мы добавили обработчик вот так addEventListener(. true) , то мы должны передать то же значение аргумента capture в removeEventListener(. true) , когда снимаем обработчик.
На каждой фазе разные обработчики на одном элементе срабатывают в порядке назначения
Если у нас несколько обработчиков одного события, назначенных addEventListener на один элемент, в рамках одной фазы, то их порядок срабатывания – тот же, в котором они установлены:
elem.addEventListener("click", e => alert(1)); // всегда сработает перед следующим elem.addEventListener("click", e => alert(2));
Итого
При наступлении события – самый глубоко вложенный элемент, на котором оно произошло, помечается как «целевой» ( event.target ).
Затем событие сначала двигается вниз от корня документа к event.target , по пути вызывая обработчики, поставленные через addEventListener(. true) , где true – это сокращение для .
Далее обработчики вызываются на целевом элементе.
Далее событие двигается от event.target вверх к корню документа, по пути вызывая обработчики, поставленные через on и addEventListener без третьего аргумента или с третьим аргументом равным false .
Каждый обработчик имеет доступ к свойствам события event :
event.target – самый глубокий элемент, на котором произошло событие.
event.currentTarget (= this ) – элемент, на котором в данный момент сработал обработчик (тот, на котором «висит» конкретный обработчик)
event.eventPhase – на какой фазе он сработал (погружение=1, фаза цели=2, всплытие=3).
Любой обработчик может остановить событие вызовом event.stopPropagation() , но делать это не рекомендуется, так как в дальнейшем это событие может понадобиться, иногда для самых неожиданных вещей.
В современной разработке стадия погружения используется очень редко, обычно события обрабатываются во время всплытия. И в этом есть логика.
В реальном мире, когда происходит чрезвычайная ситуация, местные службы реагируют первыми. Они знают лучше всех местность, в которой это произошло, и другие детали. Вышестоящие инстанции подключаются уже после этого и при необходимости.
Всплытие и погружение являются основой для «делегирования событий» – очень мощного приёма обработки событий. Его мы изучим в следующей главе.
Учебники. Программирование для начинающих.
переезд квартиры цены Прежде всего, квартирный переезд дешево – это реальность и основной принцип нашей работы. В зависимости от ваших потребностей, будь то переезд однокомнатной квартиры или трехкомнатной, мы исходим из количества вещей к перевозке. Если самостоятельно вы не имеете возможности или времени сделать опись мебели и вещей, наши специалисты вам в этом обязательно помогут.
Programm.ws — это сайт, на котором вы можете почитать литературу по языкам программирования , а так-же посмотреть примеры работающих программ на С++, ассемблере, паскале и много другого..
Программирование — в обычном понимании, это процесс создания компьютерных программ. В узком смысле (так называемое кодирование) под программированием понимается написание инструкций — программ — на конкретном языке программирования (часто по уже имеющемуся алгоритму — плану, методу решения поставленной задачи). Соответственно, люди, которые этим занимаются, называются программистами (на профессиональном жаргоне — кодерами), а те, кто разрабатывает алгоритмы — алгоритмистами, специалистами предметной области, математиками. В более широком смысле под программированием понимают весь спектр деятельности, связанный с созданием и поддержанием в рабочем состоянии программ — программного обеспечения ЭВМ. Более точен современный термин — «программная инженерия» (также иначе «инженерия ПО»). Сюда входят анализ и постановка задачи, проектирование программы, построение алгоритмов, разработка структур данных, написание текстов программ, отладка и тестирование программы (испытания программы), документирование, настройка (конфигурирование), доработка и сопровождение.
Cамоучитель по Java
Глава 6. Классы-коллекции
Как удалить элементы
Логический метод remove (Object element) удаляет из вектора первое вхождение указанного элемента element . Метод возвращает true , если элемент найден и удаление произведено.
Метод remove (int index) удаляет элемент из позиции index и возвращает его в качестве своего результата типа object .
Аналогичные действия позволяют выполнить старые методы типа void :
removeElement (Object element) И removeElementAt (int index) , не возвращающие результата.
Удалить диапазон элементов можно методом removeRange(int begin, int end) , не возвращающим результата. Удаляются элементы от позиции begin включительно до позиции end исключительно.
Удалить из данного вектора все элементы коллекции coil возможно логическим Методом removeAll(Collection coll).
Удалить последние элементы можно, просто урезав вектор методом
Удалить все элементы, кроме входящих в указанную коллекцию coil , разрешает логический метод retainAll(Collection coll).
Удалить все элементы вектора можно методом clear () или старым методом
removeAHElements () или обнулив размервектораметодомsetSize(O).
Листинг 6.1 расширяет листинг 5.2, обрабатывая выделенные из строки слова с помощью вектора.
Листинг 6.1. Работа с вектором
Vector v = new Vector();
String s = «Строка, которую мы хотим разобрать на слова.»;
StringTokenizer st = new StringTokenizer(s, » \t\n\r,.»);
// Получаем слово и заносим в вектор
v.add(st.nextToken()); // Добавляем в конец вектора
System.out.println(v.firstElement()); // Первый элемент
System.out.println(v.lastElement()); // Последний элемент
v.setSize(4); // Уменьшаем число элементов
v.add(«собрать.»); // Добавляем в конец
v.set(3, «опять»); // Ставим в позицию 3
Понимаем сленг программистов: мини-словарь для начинающих разработчиков
Начинающие разработчики не сразу понимают старших товарищей. Фразы вроде «я апишку свитчнул» или «заимпорти другую либу» звучат для новичков как лекция по математическому анализу для первобытного человека. Поэтому мы решили сделать небольшой словарь профессионального сленга программистов.
Слова и фразы в словаре отсортированы по алфавиту. Кстати, словарь можно дополнять. Пишите в комментариях термины, с которыми вы сталкивались на работе.
Бесплатные курсы по программированию в Хекслете
Освойте азы современных языков программирования
Изучите работу с Git и командной строкой
Выберите себе профессию или улучшите навыки
А
Адаптив — адаптивный дизайн, адаптация интерфейса к использованию на разных экранах.
Аджайл — от англ. Agile. Общий термин, который описывает ценности и принципы гибкой разработки программного обеспечения, а также практические подходы к разработке. Понятие Agile стало популярным после публикации Манифеста гибкой разработки программного обеспечения в 2001 году.
Айдишник — id, идентификатор.
Альфа — этап разработки программного обеспечения, на котором разработчики добавляют в программу новые функции, а тестировщики испытывают программу. Это внутренний или непубличный этап.
Апишка — API, программный интерфейс приложения или интерфейс прикладного программирования.
Апрув, апрувнуть — от англ. Approve. Одобрение, одобрить, утвердить.
Аутсорс — аутсорсинг, передача компанией части операционной деятельности другой компании.
Б
Баг — от англ. Bug — жучок, клоп. Ошибка в программе.
Бахнуть — что-то быстро сделать, изменить или дополнить функциональность приложения.
Бета — бета-версия, приложение на стадии публичного тестирования.
Бот — сокращение от «робот». Ботом называют программу, которая автоматизирует интерфейс. Пример — автоответчик в чате.
Бэкап, бэкапить — резервная копия или процесс создания резервной копии приложения.
Бэкенд — от англ. Back-end. Программно-аппаратная или серверная часть приложения.
Бэклог — от англ. Backlog. Перечень рабочих задач команды разработчиков, упорядоченный по приотритету.
В
Ворнинг — от англ. Warning — предупреждение. Предупреждающее сообщение в интерфейсе.
Войтивайти — шуточное выражение, обозначает процесс переквалификации далекого от IT-сферы специалиста в разработчика.
Выкатить — сделать доступным для пользователей. Например, «выкатили новую версию сайта» значит сделали новую версию сайта доступной для пользователей.
Выпадашка — выпадающее меню, то же, что и «дропдаун».
Г
Галера — компания, в которой платят низкие зарплаты и не ценят разработчиков.
Гит — система контроля версий Git или сервис GitHub.
Г****окод — плохой, некачественный код. Объяснение термина есть в статье нашего студента.
Градиент — плавный переход из одного цвета в другой.
Грумить — от англ. Grooming. Приводить в порядок, «причесывать».
Д
Движок — в веб-разработке так называют системы управления контентом.
Дебажить — устранять ошибки, баги.
Деплой, деплоить — развёртывание, публикация рабочей версии приложения. Пример: задеплоить сайт — перенести сайт с тестового на рабочий сервер, сделать его доступным для пользователей.
Джун, джуниор — от англ. Junior. Младший разработчик. Специалист без опыта или с минимальным опытом работы.
Дезигнер — презрительно-снисходительное название дизайнера.
Докеризировать — завернуть приложение в докер (платформу для разработки, доставки и запуска контейнерных приложений).
Драй — от англ. DRY, don’t repeat yourself. Принцип программирования, предлагающий избегать повторений кода.
Дропдаун — выпадающее меню, то же, что и «выпадашка».
Дропнуть — от англ. Drop. Удалить, отключить, сбросить или обнулить что-либо.
Ж
Жаба — язык программирования Java.
Жабаскрипт — язык программирования JavaScript.
З
Залить — загрузить. Например, «залить файлы на сервер».
Запилить — сделать что-то, добавить какую-то функциональность.
Змея — язык программирования Python.
И
Исходник — файлы, в которых находится исходный код приложения, или сам исходный код.
Итерация — повторение. «Мы сделали несколько итераций» — мы повторили шаг несколько раз.
Бесплатные курсы по программированию в Хекслете
Освойте азы современных языков программирования
Изучите работу с Git и командной строкой
Выберите себе профессию или улучшите навыки
К
Колл — от англ. Call. Созвон, онлайн-конференция, онлайн-совещание.
Коммит, коммитить — от англ. To commit — совершать. В контексте работы над приложением — сохранять код в репозитории.
Копипаста — от англ. Copy-Paste. Скопированный откуда-то код.
Костыль — код, который нужен, чтобы исправить несовершенство ранее написанного кода.
Л
Легаси — от англ. Legacy. Морально устаревший код, который не обновляется, но используется. Или код, который разработчик получил по наследству от предыдущих разработчиков.
Либа — от англ. Library — библиотека. Речь идет о библиотеках кода, например, React.
Линтер — общее нарицательное название программ, которые анализируют код и предупреждают разработчика об ошибках.
Лист — от англ. List — список.
Локалка — локальный. Например, локальный сервер или сеть.
М
Мидл — от англ. Middle — средний. Уровень разработчика, следующий за джуниором. Опыт и уровень знаний миддла позволяет ему самостоятельно решать серьезные задачи.
Мёржить — от англ. Merge, сливать. Речь идет об объединении или слиянии веток кода.
Меншить — от англ. Mention — упоминание. Упоминанать в чатах или соцсетях. «Менши меня, когда будет готово» значит «упомяни меня, когда будет готово».
Н
Навбар — навигационный блок на сайте или в интерфейсе программы.
Накатить — внести изменения, задеплоить новую версию приложения. Противоположное термину «откатить».
О
Опенсорс, опен-сорс — от англ. Open Source. Программное обеспечение с открытым исходным кодом.
Откатить — удалить изменения, вернуть предыдущую версию приложения. Противоположное термину «накатить».
Ось — операционная система.
П
Падаван — ироничное название стажера или джуниора.
Пилот — пробная (пилотная) версия продукта.
Питон — язык программирования Python.
Подвал — то же, что и «футер». Элемент структуры страницы, который находится в нижней части и содержит служебную информацию — контакты, ссылки на соцсети, публичная оферта и т. д.
Поплыла вёрстка — некорректное отображение страницы в браузере.
Продакшн или продакшен (продакшн-код) — обозначение кода для рабочей версии приложения.
Пушить — использовать команду push, публиковать что-то.
Пэхапэ — язык программирования PHP, то же, что и «пыха».
Пыха — язык программирования PHP, то же, что и «пэхапэ».
Р
Рекурсия — описание процесса с помощью самого процесса. Например, выражение «рекурсивный вызов функции» описывает ситуацию, в которой функция вызывает сама себя.
Релиз — программное обеспечение на стадии публичного использования. Стабильная версия программы, которая прошла тестирование.
Релокация — перевод сотрудника или бизнеса в другое место внутри страны или за границу.
Репа — репозиторий, хранилище данных. Например, код программы можно хранить в репозитории на GitHub.
Ридми — файл Readme, в котором содержится информация о программе.
Ругаться, например, линтер ругается — сообщения об ошибках в коде, работе сервиса и так далее.
С
Сабж — от английского Subject — тема, предмет. «По сабжу» — по теме обсуждения.
Свитчнуть, свичнуть — переключить. От английского switch.
Сетка — модульная сетка, используется для дизайна и верстки страниц.
Сеньор, синьор — от англ. Senior — старший разработчик.
Сорец (Сорцы) — от англ. Source. Исходный код.
Стек — изначально абстрактный тип данных. В разговорной речи используется для обозначения списка технологий, которые использует разработчик или компания. Пример: «Наш стек — HTML/CSS, JavaScript, React».
Софт — от англ. Software — программное обеспечение.
Софт-скиллы — от англ. Soft skills — знания и качества специалиста, прямо не связанные с профессиональной деятельностью. Примеры: коммуникабельность, проактивность.
Спринт — короткий промежуток времени (до 4 недель), в течение которого scrum-команда выполняет определенный объем работы.
Читайте также: Как джуну найти работу и где лучше начинать карьеру в IT: советы от Хекслета
Т
Таска — от англ. Task. Задание, задача.
Темплейт — от английского Template — шаблон.
Тестировщик — специалист по тестированию программного обеспечения.
Тимлид — от английского Team Lead — руководитель команды. Координатор группы программистов.
У
Убить — удалить что-то. Например, «убить профиль» означает удалить профиль.
Ф
Фидбек — от англ. Feedback — обратная связь.
Фиксить, пофиксить — от англ. Fix. Чинить, починить, исправить.
Фича — функция, возможность. От англ. Feature.
Фреймворк — от англ. Framework — каркас. Инструмент разработки, набор типовых шаблонных решений, упрощающих работу программиста. Примеры: Laravel, Bootstrap.
Фронтенд — от англ. Front-end — клиентская часть приложения.
Х
Хатэмээль, хатээмэль — HTML, язык гипертекстовой разметки.
Хардкодить — статически прописывать в коде данные, которые должны вычисляться динамически. Плохая практика, антипаттерн в программировании.
Хацкер, кулхацкер — ироничное название начинающего специалиста, который считает себя опытным программистом. От английского Hacker и Cool Hacker.
Хедер, хэдер — элемент структуры веб-страницы, находится в верхней части и содержит логотип, меню, служебную информацию.
Хотфикс — от англ. Hotfix. Срочное исправление критических ошибок, уязвимостей или недоработок в программе.
Ц
Цэмээс, цээмэс — от англ. CMS — Content Management System, система управления контентом.
Чекать, чекнуть, прочекать — от англ. Check. Проверять, проверить.
Ю
Юзать — от английского To use — использовать.
Я
Ява — язык программирования Java.
Яваскрипт — язык программирования JavaScript.
ЯП — язык программирования.
Бесплатные курсы по программированию в Хекслете
Освойте азы современных языков программирования
Изучите работу с Git и командной строкой
Выберите себе профессию или улучшите навыки
О стеке простыми словами — для студентов и просто начинающих
Привет, я студент второго курса технического университета. После пропуска нескольких пар программирования по состоянию здоровья, я столкнулся с непониманием таких тем, как «Стек» и «Очередь». Путем проб и ошибок, спустя несколько дней, до меня наконец дошло, что это такое и с чем это едят. Чтобы у вас понимание не заняло столько времени, в данной статье я расскажу о том что такое «Стек», каким образом и на каких примерах я понял что это такое. Если вам понравится, я напишу вторую часть, которая будет затрагивать уже такое понятие, как «Очередь»
Теория
На Википедии определение стека звучит так:
Стек (англ. stack — стопка; читается стэк) — абстрактный тип данных, представляющий собой список элементов, организованных по принципу LIFO (англ. last in — first out, «последним пришёл — первым вышел»).
Достаточно полное определение, но возможно для новичков оно будет немного трудным для понимания.
Поэтому первое, на чем бы я хотел заострить внимание, это представление стека в виде вещей из жизни. Первой на ум мне пришла интерпретация в виде стопки книг, где верхняя книга — это вершина.
На самом деле стек можно представить в виде стопки любых предметов будь то стопка листов, тетрадей, рубашек и тому подобное, но пример с книгами я думаю будет самым оптимальным.
Итак, из чего же состоит стек.
Стек состоит из ячеек(в примере — это книги), которые представлены в виде структуры, содержащей какие-либо данные и указатель типа данной структуры на следующий элемент. Сложно? Не беда, давайте разбираться.
На данной картинке схематично изображен стек. Блок вида «Данные/*next» и есть наша ячейка. *next, как мы видим, указывает на следующий элемент, другими словами указатель *next хранит адрес следующей ячейки. Указатель *TOP указывает на вершину стек, то есть хранит её адрес.
С теорией закончили, перейдем к практике.
Практика
Для начала нам нужно создать структуру, которая будет являться нашей «ячейкой»
Код на C++
struct comp < //Структура с названием comp(от слова component) int Data; //Какие-то данные(могут быть любыми, к примеру можно написать int key; char Data; так-же можно добавить еще какие-либо данные) comp *next;//Указатель типа comp на следующий элемент >;
Новичкам возможно будет не понятно, зачем наш указатель — типа comp, точнее сказать указатель типа структуры comp. Объясню, для того чтобы указатель *next мог хранить структуру comp, ей нужно обозначить тип этой структуры. Другими словами указать, что будет хранить указатель.
После того как у нас задана «Ячейка», перейдем к созданию функций.
Функции
Функция создания «Стека»/добавления элемента в «Стек»
При добавлении элемента у нас возникнет две ситуации:
Стек пуст, и нужно создать его
Стек уже есть и нужно лишь добавить в него новый элемент
Код на C++
void s_push(comp **top, int D) < //функция типа void(ничего не возвращает) которая принимает указатль на вершину стека и переменную которая будет записываться в ячейку comp *q; //Создаем новый указатель q типа структуры comp. По сути это и есть наш новый элемент q = new comp(); //выделяем память для нового элемента q->Data = D; //Записываем необходимое число в Data элемента if (top == NULL) < //Если вершины нет, то есть стек пустой *top = q; //вершиной стека будет новый элемент >else //если стек не пустой < q->next = *top; //Проводим связь от нового элемента, к вершине. Тоесть кладем книжку на вершину стопки. *top = q; //Обозначаем, что вершиной теперь является новый элемент > >
Разберем чуть чуть по-подробнее. Во-первых, почему функция принимает **top, то есть указатель на указатель, для того чтобы вам было наиболее понятно, я оставлю рассмотрение этого вопроса на потом. Во-вторых, по-подробнее поговорим о q->next = *top и о том, что же означает ->.
-> означает то, что грубо говоря, мы заходим в нашу структуру и достаем оттуда элемент этой структуры. В строчке q->next = *top мы из нашей ячейки достаем указатель на следующий элемент *next и заменяем его на указатель, который указывает на вершину стека *top. Другими словами мы проводим связь, от нового элемента к вершине стека. Тут ничего сложного, все как с книгами. Новую книгу мы кладем ровно на вершину стопки, то есть проводим связь от новой книги к вершине стопки книг. После этого новая книга автоматически становится вершиной, так как стек не стопка книг, нам нужно указать, что новый элемент — вершина, для этого пишется: *top = q;.
Функция удаления элемента из «Стека» по данным
Данная функция будет удалять элемент из стека, если число Data ячейки(q->Data) будет равна числу, которое мы сами обозначим.
Здесь могут быть такие варианты:
Ячейка, которую нам нужно удалить является вершиной стека
Ячейка, которую нам нужно удалить находится в конце, либо между двумя ячейками
Код на C++
void s_delete_key(comp **top, int N)/функция которая принимает вершину top и число которое нужно удалить comp *q = *top; //создаем указатель типа comp и приравниваем(ставим) его на вершину стека comp *prev = NULL;//создаем указатель на предыдуший элемент, с начала он будет пустым while (q != NULL) /пока указатель q не пустой, мы будем выполнять код в цикле, если он все же пустой цикл заканчивается if (q-> Data == N)/если Data элемента равна числу, которое нам нужно удалить if (q == *top) /если такой указатель равен вершине, то есть элемент, который нам нужно удалить - вершина *top = q-> next;//передвигаем вершину на следующий элемент free(q);//очищаем ячейку q->Data = NULL; //Далее во избежание ошибок мы обнуляем переменные в удаленной ячейке, так как в некоторых компиляторах удаленная ячейка имеет переменные не NULL значения, а дословно "Чтение памяти невозможно" или числа "-2738568384" или другие, в зависимости от компилятора. q->next = NULL; > else//если элемент последний или находится между двумя другими элементами < prev->next = q->next;//Проводим связь от предыдущего элемента к следующему free(q);//очищаем ячейку q->Data = NULL;//обнуляем переменные q->next = NULL; > >// если Data элемента НЕ равна числу, которое нам нужно удалить prev = q; //запоминаем текущую ячейку как предыдущую q = q->next;//перемещаем указатель q на следующий элемент > >
Указатель q в данном случае играет такую же роль, что и указатель в блокноте, он бегает по всему стеку, пока не станет равным NULL(while(q != NULL)), другими словами, пока стек не закончится.
Для лучшего понимания удаления элемента проведем аналогии с уже привычной стопкой книг. Если нам нужно убрать книгу сверху, мы её убираем, а книга под ней становится верхней. Тут то же самое, только в начале мы должны определить, что следующий элемент станет вершиной *top = q->next; и только потом удалить элемент free(q);
Если книга, которую нужно убрать находится между двумя книгами или между книгой и столом, предыдущая книга ляжет на следующую или на стол. Как мы уже поняли, книга у нас-это ячейка, а стол получается это NULL, то есть следующего элемента нет. Получается так же как с книгами, мы обозначаем, что предыдущая ячейка будет связана с последующей prev->next = q->next;, стоит отметить что prev->next может равняться как ячейке, так и нулю, в случае если q->next = NULL, то есть ячейки нет(книга ляжет на стол), после этого мы очищаем ячейку free(q).
Так же стоит отметить, что если не провести данную связь, участок ячеек, который лежит после удаленной ячейки станет недоступным, так как потеряется та самая связь, которая соединяет одну ячейку с другой и данный участок просто затеряется в памяти
Функция вывода данных стека на экран
Самая простая функция:
Код на C++
void s_print(comp *top) < //принимает указатель на вершину стека comp *q = top; //устанавливаем q на вершину while (q) < //пока q не пустой (while(q) эквивалентно while(q != NULL)) printf_s("%i", q->Data);//выводим на экран данные ячейки стека q = q->next;//после того как вывели передвигаем q на следующий элемент(ячейку) > >
Здесь я думаю все понятно, хочу сказать лишь то, что q нужно воспринимать как бегунок, он бегает по всем ячейкам от вершины, куда мы его установили вначале: *q = top;, до последнего элемента.
Главная функция
Хорошо, основные функции по работе со стеком мы записали, вызываем. Посмотрим код:
Код на C++
void main() < comp *top = NULL; //в начале программы у нас нет очереди, соответственно вершины нет, даем ей значение NULL //Дальше начинаем добавлять цифры от 1 до 5 в наш стек s_push(&top, 1); s_push(&top, 2); s_push(&top, 3); s_push(&top, 4); s_push(&top, 5); //после выполнения функций в стеке у нас будет 54321 s_print(top);//выводим s_delete_key(&top, 4); //Затем удаляем 4, в стеке получается 5321 printf_s("\n");//переводим на новую строку s_print(top);//выводим system("pause");//ставим на паузу >
Вернемся к тому, почему же в функцию мы передавали указатель на указатель вершины. Дело в том, что если бы мы ввели в функцию только указатель на вершину, то «Стек» создавался и изменялся только внутри функции, в главной функции вершина бы как была, так и оставалась NULL. Передавая указатель на указатель мы изменяем вершину *top в главной функции. Получается если функция изменяет стек, нужно передавать в нее вершину указателем на указатель, так у нас было в функции s_push,s_delete_key. В функции s_print «Стек» не должен изменяться, поэтому мы передаем просто указатель на вершину. Вместо цифр 1,2,3,4,5 можно так-же использовать переменные типа int.
Заключение
Полный код программы:
Код на C++
#include ; #include ; struct comp < //Структура с именем comp int Data; //Кикие то данные(могут быть любими, к примеру можно написать int key; char Data; или добавить еще какие то данные) comp *next;//Указатель типа comp на следующий эелемент >; void s_push(comp **top, int D) < //функция типа void(ничего не возвращает) которая принимает указатль на вершину стека и переменную которая будет записываться в ячейку comp *q; //Создаем новый указатель q, который приравниваем к вершине стека. По сути это и есть наш новый элемент q = new comp(); //выделяем память для нового элемента q->Data = D; //Записываем D в Data элемента if (top == NULL) < //Если вершины нет, тоесть стек пустой *top = q; //вершиной стека будет новый элемент >else //если стек не пустой < q->next = *top; //Проводим связь от нового элемента, к вершине. Тоесть кладем книжку на вершину стопки. *top = q; //Пишем, что вершиной теперь является новый элемент > > void s_delete_key(comp **top, int N)/функция которая принимает вершину top и число которое нужно удалить comp *q = *top; //создаем указатель типа comp и приравниваем(ставим) его на вершину стека comp *prev = NULL;//создаем указатель на предыдуший элемент, с начала он будет пустым while (q != NULL) /пока указатель q не путой, мы его будем проверять, если он все же пусть цикл заканчивается if (q-> Data == N)/если Data элемента равна числу, которое нам нужно удалить if (q == *top) /если такой указатель равен вершине, то есть элемент, который нам нужно удалить - вершина *top = q-> next;//передвигаем вершину на следующий элемент free(q);//очищаем ячейку q->Data = NULL; //Далее во избежание ошибок мы обнуляем переменные в удаленной ячейке, так как в некоторых компиляторах удаленная ячейка имеет переменные не NULL значения, а дословно "Чение памяти невозможно" или числа "-2738568384" или других, в зависимости от компилятора. q->next = NULL; > else//если элемент последний или находится между двумя другими элементами < prev->next = q->next;//Проводим связь от предыдущего элемента к следующему free(q);//очищаем ячейку q->Data = NULL;//обнуляем переменные q->next = NULL; > >// если Data элемента НЕ равна числу, которое нам нужно удалить prev = q; //запоминаем текущую ячейку как предыдущую q = q->next;//перемещаем указатель q на следующий элемент > > void s_print(comp *top) < //принимает указатель на вершину стека comp *q = top; //устанавливаем q на вершину while (q) < //пока q не пустой (while(q) эквивалентно while(q != NULL)) printf_s("%i", q->Data);//выводим на экран данные ячейки стека q = q->next;//после того как вывели передвигаем q на следующий элемент(ячейку) > > void main() < comp *top = NULL; //в начале программы у нас нет очереди, соответственно вершины нет, даем ей значение NULL //Дальше начинаем добавлять цифры от 1 до 5 в наш стек s_push(&top, 1); s_push(&top, 2); s_push(&top, 3); s_push(&top, 4); s_push(&top, 5); //после выполнения функций в стеке у нас будет 54321 s_print(top);//выводим s_delete_key(&top, 4); //Затем удаляем 4, в стеке получается 5321 printf_s("\n");//переводим на новую строку s_print(top);//выводим system("pause");//ставим на паузу >
54321 5321
Так как в стек элементы постоянно добавляются на вершину, выводиться элементы будут в обратном порядке
В заключение хотелось бы поблагодарить за уделенное моей статье время, я очень надеюсь что данный материал помог некоторым начинающим программистам понять, что такое «Стек», как им пользоваться и в дальнейшем у них больше не возникнет проблем. Пишите в комментариях свое мнение, а так же о том, как мне улучшить свои статьи в будущем. Спасибо за внимание.