Advertisement
Guest User

XOR-связный спсок

a guest
Nov 4th, 2011
422
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 11.15 KB | None | 0 0
  1. /*
  2.     Программа демонстрации циклического двунаправленного списка
  3.     с использованием XOR-адресации.
  4. */
  5.  
  6. #include <cstring>
  7. #include <cstdlib>
  8. #include <iostream>
  9. #include <cstddef>
  10.  
  11. using namespace std;
  12.  
  13. typedef uintptr_t INT_P;
  14. // INT_PTR уже был, но мы же хотим кросслпатформенно.
  15. // да можно было сразу uintptr_t везде писать, но сейчас уже поздно.
  16. // Пусть так остаётся.
  17.  
  18. #define K_NEXT 'n'
  19. #define K_BACK 'b'
  20. #define K_DEL 'd'
  21. #define K_INS 'i'
  22. #define K_END 'e'
  23. #define K_NOTUSED 'u'
  24. // Выше -- буквы для управления.
  25.  
  26. #define END_STR "end"
  27. // Строка для прекращения ввода.
  28.  
  29.  
  30. // Структура для хранения данных. Можно было сделать через шаблоны (лень).
  31. // Можно было зашить её в класс списка (неуниверсально).
  32. struct data_struct
  33.     {
  34.         char title[80]; // Заголовок элемента.
  35.         int value; // Значение, с ним связанное. На самом деле тут будет идентификатор элемента (номер).
  36.     };
  37.  
  38. // Структура элемента списка.
  39. struct x_list_entry
  40.     {
  41.         void *data; // Указатель на данные. Что угодно. Здесь -- data_struct
  42.         INT_P x_address; // XOR-адрес. Для определённости и нетавталогии будем называть его "ёж".
  43.     };
  44.  
  45. // Класс списка -- x_list
  46. class x_list
  47.     {
  48.         private:
  49.             // Т.к. для навигации нужно знать два последовательных элемента, будем хранить оба.
  50.             x_list_entry *entry1; // Первый. Считается "текущим элементом".
  51.             x_list_entry *entry2; // Второй.
  52.             unsigned int n; // Размер списка
  53.         public:
  54.             void next(void); // Прокрутить вперёд.
  55.             void prev(void); // Прокрутить назад.
  56.             void *get(void); // Получить адрес данных текущего элемента.
  57.             void insert(void *data); // Вставить данные по адресу как новый элемент после текущего
  58.             unsigned int erase(void); // Стереть текущий элемент.
  59.             inline unsigned int size(void){return n;}; // Получить размер списка.
  60.             x_list(void); // Конструктор.
  61.             ~x_list(void); // Деструктор.
  62.     };
  63.  
  64. // Конструктор класса x_list .
  65. x_list::x_list()
  66.     {
  67.         // Создаём первые два элемента
  68.         // (если в списке меньше двух элементов, происходит специальная обработка,
  69.         // фактически хотя бы два элемента есть, но снаружи этого не видно).
  70.         entry1=new x_list_entry;
  71.         entry2=new x_list_entry;
  72.         // Размер равен нулю.
  73.         n=0;
  74.         // Если у двух соседних элементов ежи равны нулю, то они ссылаются друг на друга.
  75.         entry1->x_address=NULL;
  76.         entry2->x_address=NULL;
  77.     }
  78.  
  79. // Деструктор класса x_list .
  80. x_list::~x_list()
  81.     {
  82.         // Удаляем пока есть что. Обратите внимание, указатели с данными должны быть
  83.         // обработаны пользователем. Класс не знает какой там тип, поэтому не может
  84.         // вызвать деструктор. Через шаблоны это можно было бы сделать.
  85.         while(n>0)
  86.             erase();
  87.         // Удаляем последние два элемента (при обычном удалении их удалить нельзя,
  88.         // там же спецобработка!
  89.         delete entry1;
  90.         delete entry2;
  91.     }
  92.  
  93. // Перемещение вперёд по списку.
  94. void x_list::next(void)
  95.     {
  96.         // Спецобработка: если 0 элементов, перемещаться некуда, если 1 элемент, мы на нём
  97.         // и остаёмся.
  98.         if(n<2)
  99.             return;
  100.         x_list_entry *temp; // Для временного хранения старого текущего элемента.
  101.         temp=entry1; // Сохранили.
  102.         entry1=entry2; // Теперь текущий -- второй (двигаемся вперёд).
  103.         entry2=reinterpret_cast<x_list_entry*>((reinterpret_cast<INT_P>(temp))^(entry1->x_address));
  104.         // Вычисляем, где новый второй, с использованием текущего и старого текущего.
  105.     }
  106.  
  107. // Перемещение назад по списку.
  108. void x_list::prev(void)
  109.     {
  110.         // Спецобработка: если 0 элементов, перемещаться некуда, если 1 элемент, мы на нём
  111.         // и остаёмся.
  112.         if(n<2)
  113.             return;
  114.         x_list_entry *temp; // Для временного хранения старого второго элемента.
  115.         temp=entry2; // Сохранили.
  116.         entry2=entry1; // Теперь второй -- текущий (двигаемся назад)
  117.         entry1=reinterpret_cast<x_list_entry *>((reinterpret_cast<INT_P>(temp))^(entry2->x_address));
  118.         // Вычиляем, где новый текущий, с использованием второго и старого второго.
  119.     }
  120.  
  121. // Получение адреса данных.
  122. void *x_list::get(void)
  123.     {
  124.         // Если пусто, возвращаем NULL.
  125.         if(n==0)
  126.             return NULL;
  127.         // Если не пусто, возвращаем адрес на данные текущего элемента.
  128.         return entry1->data;
  129.     }
  130.  
  131. // Добавление элемента.
  132. void x_list::insert(void *data)
  133.     {
  134.         // Эта операция выполняется всегда, даже в случае спецобработки, поэтому делаем
  135.         // её с начала: увеличиваем размер списка.
  136.         n++;
  137.         if(n==1) // Если размер стал равен одному, список был пустым.
  138.             {
  139.                 entry1->data=data; // Пишем данные в текущий элемент.
  140.                 return;
  141.             }
  142.         if(n==2) // Если размер стал равен двум, был один элемент.
  143.             {
  144.                 entry2->data=data; // Пишем данные во второй элемент.
  145.                 next(); // Прокручиваем список, делая новый текущим.
  146.                 return;
  147.             }
  148.  
  149.         x_list_entry *temp; // Временный элемент, который скоро войдёт в список
  150.         temp=new x_list_entry; // Выделяем ему память.
  151.         temp->data=data; // Пишем данные.
  152.         // Определяем ёж нового элемента.
  153.         temp->x_address=(reinterpret_cast<INT_P>(entry1))^(reinterpret_cast<INT_P>(entry2));
  154.         // Теперь надо пересчитать ежи соседних.
  155.         entry2->x_address=(reinterpret_cast<INT_P>(temp))^((entry2->x_address)^(reinterpret_cast<INT_P>(entry1)));
  156.         entry1->x_address=(reinterpret_cast<INT_P>(temp))^((entry1->x_address)^(reinterpret_cast<INT_P>(entry2)));
  157.         entry2=temp; // Новый элемент теперь вместо второго.
  158.         next(); // Прокручиваем список, делая новый текущим.
  159.     }
  160.  
  161. // Удаление элемента из списка.
  162. unsigned int x_list::erase()
  163.     {
  164.         // Спецобработка.
  165.         if(n==0)
  166.             return 0; // Пустой список пуще не станет.
  167.         if(n==1) // Если оставался 1 элемент, просто говорим, что стало 0.
  168.             return --n;
  169.         if(n==2) // Если оставалось 2 элемента, прокручиваем список и говорим что осталось 1.
  170.             {
  171.                 next();
  172.                 return --n;
  173.             }
  174.         // Тут спецобработка заканчивается и надо уже что-то удалять.
  175.         x_list_entry *temp; // Тут будем хранить предыдущий элемент
  176.         temp=reinterpret_cast<x_list_entry*>((entry1->x_address)^(reinterpret_cast<INT_P>(entry2)));
  177.         temp->x_address=(temp->x_address^(reinterpret_cast<INT_P>(entry1)))^(reinterpret_cast<INT_P>(entry2));
  178.         // Нашли элемент, пересчитали его ёж с учётом что текущего элемента больше нет.
  179.         entry2->x_address=(entry2->x_address^(reinterpret_cast<INT_P>(entry1)))^(reinterpret_cast<INT_P>(temp));
  180.         // Пересчитали ёж второго элемента с учётом того же.
  181.         delete entry1; // Удаляем текущий, нас ничто не держит.
  182.         entry1=temp; // Теперь текущий -- предыдущий.
  183.         next(); // Прокрутим, чтобы текущим стал второй, так логичнее.
  184.         return --n; // Уменьшили размер и вернули новый.
  185.  
  186.     }
  187.  
  188. // Программа-демонстрация. Тут уже почти без пояснений.
  189.  
  190. int main(int argc, char* argv[])
  191.     {
  192.         x_list list;
  193.         char user_input[80];
  194.         char key=K_NOTUSED;
  195.         bool exit_flag=false;
  196.         data_struct *d;
  197.         int id=0;
  198.  
  199.         // ФАЗА 1. Заполнение списка.
  200.  
  201.         cout << "Enter list entries, one per line, \"" << END_STR << "\" to stop.\n";
  202.         do
  203.             {
  204.                 cout << "("<<list.size()<<"):";
  205.                 cin >> user_input;
  206.                 d=new data_struct;
  207.                 strcpy(d->title,user_input);
  208.                 d->value=id++;
  209.                 list.insert(d);
  210.             }
  211.         while(strcmp(user_input,END_STR)!=0); // Пока не введут условное кодовое слово. Слово добавляется в список.
  212.  
  213.         // ФАЗА 2. Управление списком.
  214.  
  215.         cout << "List control: " << K_NEXT << "=NEXT, " << K_BACK << "=BACK, " << K_DEL << "=DELETE CURRENT, " << K_INS << "=INSERT NEW, " << K_END << "=EXIT.\n";
  216.         while(!exit_flag) // Цикл работы со списком.
  217.             {
  218.                 if(isalpha(key))
  219.                     if(!list.get())
  220.                         cout << "EMPTY LIST\n";
  221.                     else
  222.                         cout <<"("<<key<<") Size="<<list.size()<<";["<<((data_struct *)list.get())->value<<"]:"<<((data_struct *)list.get())->title<<"\n";
  223.                 key=getchar();
  224.                 switch(key) // Обработка команд.
  225.                     {
  226.                         case K_NEXT:
  227.                             list.next();
  228.                             break;
  229.                         case K_BACK:
  230.                             list.prev();
  231.                             break;
  232.                         case K_DEL:
  233.                             delete ((data_struct *)list.get());
  234.                             list.erase();
  235.                             break;
  236.                         case K_INS:
  237.                             cout << "Enter new element:";
  238.                             cin >> user_input;
  239.                             d=new data_struct;
  240.                             strcpy(d->title,user_input);
  241.                             d->value=id++;
  242.                             list.insert(d);
  243.                             break;
  244.                         case K_END:
  245.                             exit_flag=true;
  246.                             break;
  247.                         default:
  248.                             if(isalpha(key))
  249.                                 cout << "List control: " << K_NEXT << "=NEXT, " << K_BACK << "=BACK, " << K_DEL << "=DELETE CURRENT, " << K_INS << "=INSERT NEW, " << K_END << "=EXIT.\n";
  250.                             break;
  251.                     }
  252.             }
  253.         return 0;
  254.     }
  255.  
  256.  
  257.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement