Суббота, 19.07.2025, 07:19
Приветствую Вас Гость | RSS
Главная | Каталог статей | Регистрация | Вход
.:: Меню ::.
.:: Категории каталога ::.
Разное [5]
Различные темы по программированию
Пакет SWT [4]
Практикуемся в написании оконных приложений на Java
Среды разработки, компиляторы и т.п [3]
Сравнения, описания, плюсы и минусы сред разработки. Сравнение компиляторов.
Java [8]
Объектно-ориентированные соображения.
Си++ [19]
Коротко и ясно
Ассемблер [6]
Машинные коды, побитно :)
Форма входа
.:: Поиск ::.
.:: Дополнительно ::.
    Хостинг от Loqo.ru
             .:: Коментируем ::.
Главная » Статьи » Текстовый материал » Си++

Работа с двусвязным списком

Линейный двусвязный список из четырёх элементов.
Обращу внимание, что указатели содержат адреса начала структуры в памяти, т.е. графически, стрелки должны указывать на начало прямоугольников. Когда рисовал схемку не придал этому большого значения, но всё-таки обращу на это внимание. (это касается стрелок обратных указателей и указателя конца списка)
Начнём пожалуй.
Особо код не вылизывал, да и не стремился сделать супер программу.
Code

#include <iostream>
using namespace std;

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
typedef struct element
{
  element* prev; char inf; element* next;
} NODE;  

//Поля структуры я расположил так намеренно для ясности
//Определяем синоним нашей структуре, кстати размер структуры 12 байт
//По сути должно быть 9, два 4-х байтных указателя и и один однобайтный символ
//Машины не очень любят нечётные числа, думаю значение специально выравнено
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

//Формирование списка
//Функция возвращает указатель на сформированный узел
NODE* forming_list ()
{
  NODE* addElement = NULL;
  //NULL - это синоним 0-я (#define NULL 0) вот так это делается, а вообще это значит что элемент не имеет определённого значения
  NODE* tempElement;
  char ch; //Символ

  do // делать (дословный перевод)
  {
  tempElement=new(NODE); //Выделяем память в куче под новый узел, переменная temp содержит адрес, т.к. temp - Это указатель
  //Ну вот, мы создали элемент списка
  cout << "Адресс переменной temp = " << tempElement << endl; //Куда его запихнула ОС
  tempElement->next=addElement;  
  // обращаемся к полям структуры через стрелку, так как temp - указатель
  // указатель next теперь указывает на элемент переданный через параметр в функцию
  tempElement->prev=NULL; //Это первый элемент списка, поэтому слева он не ссылается на другой элемент
  // на предыдущий элемент не ссылаемся
  cout<<"Введите символ ('*'-закончить ввод):"; //выводим надпись
  cin>>ch; //вводим символ
  tempElement->inf=ch; //сохраняем символ в элементе
  addElement=tempElement; //теперь, начинаем плясать от temp
  // if(tempElement->prev!=NULL) tempElement->prev->next=tempElement;  
  //Вот тут глвное сильно не напрягать мозги, если не понятно, будем разжёвывать

  } while(ch!='*'); // (пока ввёдённый символ не окажется звёздочкой)
  cout << "\n Конец списка\n";
  return tempElement; //Возвращаем список
}

//Выводим содержимое списка с элемента inputE
void out_list (NODE* inputE)
{
  NODE* temp;
  temp = inputE->next;
  cout << "\n\n Распечатка списка:\n\n";
  do
  {
  cout << "" << temp->inf;
  temp=temp->next;
  }
  while(temp!=NULL);
}

//Добавить элемент после последнего
void addElementToRigth(NODE* list, char inf)  
{  
  NODE* listTemp = new NODE; //Указатель на область памяти, где хранится новый узел
  listTemp->inf = inf; //Заполняем узел
  listTemp->prev = list; //Слева у нас остаётся элемент писка в который мы делаем вставку
  listTemp->next = list->next;  
  //Наш вставляемый элемент будет теперь ссылаться на элемент, на котороый ссылался элемент списка
  //в который мы вставляем элемент (звучит бредово, но понять можно)
  list->next = listTemp; //Наш элемент становится следующим элементом списка
  listTemp->next->prev = listTemp;  
}  

void main(void)
{
  setlocale (LC_ALL, "rus");
  cout << "Размер структуры NODE = " << sizeof(NODE) << endl;
  NODE* top = forming_list(); //Формируем список используя top;  
  //top - первый элемент, от которого мы попляшем немного
  cout<<"Адрес переменной top после формирования ="<<top;
  out_list (top);
  addElementToRigth(top->next, 'z');
  out_list(top); //Выводим список после вставки элемента
  cout<<"\n\n Конец программы\n";
  system ("pause");
}

Программа представляет из себя смесь Си и Си++ (Си больше), вывод на консоль и ввод выполним с помощью прастранства имён std конечно же как это пологается в Си++.

Функция main содержит в себе вызовы троечки интересующих нас функций для создания и использования списка.
Первая (NODE* forming_list ()) функция формирует список и возвращает указатель на последний элемент списка.
Функция (void out_list (NODE* inputE)) выводит список начиная с элемента inputE
Функция (void addElementToRigth(NODE* list, char inf)) добавляет элемент следом за элементом list

Вообще эта тема очень интересная, но если в неё очень сильно начать вникать сходу, то может получиться кашица в голове.
Во-первых нужно чётко представлять себе, что данные хранятся в памяти и что указатель это переменная хранящая адрес начала участка памяти, где хранятся наши данные.
Итак, наши данные.
Список в нашей программе представляет собой структуру с тремя переменными, двумя указателями на эту же структуру и одним символом.
Формирование списка начинается с создания в куче экземпляра нашей структуры и установкой его указателей на самого себя (изначально указатели указывают на NULL)
Единственный элемент созданный в списке ссылается на себя.
В этой программе имеется недоработка, при добавлении элемента к списку из одного элемента повергнет программу в дикий ужас с ошибкой доступа к памяти. (Ну это уже вам дорабатывать если понадобится)

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

Добавление элемента совершается довольно элементарно, создаётся экземпляр структуры и путём манипуляции с указателями элемент магическим образом оказывается вставленным в список.
В этой программе элемент добавляется после первого элемента, так как в параметр функции добавляющую новый элемент мы засылаем адрес (указатель ) первого элемента.
После формирования списка в переменной top оказывается адрес первого элемента.
При выводе списка на экран мы используем эту-же переменную.
Ну вот в вкратце вроде бы и всё.
В коде есть комментарии, возможно не особо отражающие суть, но нужные.
Хотел эту статью изначально расписать во всех красках, со скриншотами точек останова и содержимым переменных, но, к сожалению осознал, что это займёт много времени, которого у меня не хватает.


Поэтому, желаю удачи.

Кстати первым элементом становится последний символ который вы введёте, изучите это. Ну и воспользуйтесь отладкой, точками останова для более детального понимания.
Будет время, попробую довести до ума статью.

Категория: Си++ | Добавил: C0demaker (26.05.2010)
Просмотров: 4341 | Рейтинг: 0.0/0
Всего комментариев: 0

Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Ant1 © 2025