Модераторы: Daevaorn
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Help!!! Динамические структуры. Не пашет как должно... 
:(
    Опции темы
student0511
  Дата 28.8.2006, 14:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 42
Регистрация: 26.3.2006

Репутация: нет
Всего: нет



Приветствую ALL!!!
   Моё сообщение уже было представлена в теме "Указатели на структуры". Но с проблемой так и не разобрался....  smile 
  Сравнительно недавно начал изучать С/С++ и перешёл к указателям (весьма весёлая вещь  smile  ).  Наткнулся на динамические структуры данных и до сих пор изучаю их,  да уж очень интересно…  smile 
   Для простоты я использую только одно поле: int digital. В программе всего несколько функций: вывод списка, поиск и удаление элементa(ов), вставка, печать в обратном порядке -  проблема заключается в удалении элемента, вставленного в середину списка. Поиск организуется путём перебора исходных данных, если «объект» повторяется (в данном случае целое число), то создаётся новый линейный список с более, чем одним элементом   (он  формируется в любом случае), каждый элемент которого указывает на свой исходник (->prvs) и возвращается указатель на него. В функции удаление, если это элемент - ни конец списка, ни его начало, то происходит вставка элемента в середину, а удаляет следующия функция:

Код

order* delt (order*& beg, order*& end, int* nb)
{
order* del = find(beg, &*nb);
order* kill = 0;
/////////////////////////////////
 while(del) //// листаем список удаляемых элементов
 {
  if(del->prvs == beg) /// если элемент в начале
    {
    beg = beg->p;
    beg->prvs=0;
    }
    else 
        if(del->prvs == end)// в конце
               {   
                end = end->prvs;
                end->p = 0;
               }
                else// в середине
                {
                 ((del->prvs)->prvs)->p = (del->prvs)->p;/// связываем предыдущий удаляемому элемент с последующим,
                 cout<<"\n111 "<<((del->prvs)->prvs)->p->d<<endl;
                 ((del->prvs)->p)->prvs =  (del->prvs)->prvs;///??????????????????// и наоборот, только не пашет. 
                 cout<<"\n222 "<<(del->prvs)->prvs->d<<endl;///(del->prvs)->prvs->d = del->prvs->d???///
                }
 del = del->p;// проворачиваем далее.
}
 while(del)
 {
  del = kill;
  delete(del);
  kill = kill->p;
 }
return (beg);// возвращаем указатель на новую структуру данных.                     
}
 
    Где del  - указатель на список, который формируется для удаления  повторяющихся  полей в исходном списке – очереди (order). Beg and end – как понятно из названия, являются указателями на начало и конец в исходном списке. При формировании вспомогательной динамической структуры используется основа исходной. Так указатель “->p” содержит адрес след.  элемента, а вот “->prvs” уже играет другую роль, нежели в очереди order: он отвечает за координаты исходных элементов, из которых и формируется вспомогательный список. В результате, зная всё об исходнике, его легко удалить.
    При чём выражение (del->prvs)->prvs всё равно указывает не на «объект», предшествующий исходному, а вообще непонятно на что. При выводе (del->prvs)->prvs->d
возвращает число, которое необходимо удалить.
    Функция вставки:
Код

order* input (order*& beg, order*& end, int* nb, int* k)
{
order* pv = new order;// выделяем память под вставляемый элемент и запоминаем адрес его в указателе pv
order* pos = find(beg, &*k);// поиск позиции
pv->d = *nb;// информационное поле новичка. «Объёмное»…
int f = 1;
/////////////////////////////////
while(pos && f)///листаем вспом. список  один раз
{
 if(pos->prvs == beg)// если «позиция» в начале
 {
  pv->p = beg;
  beg->prvs = pv;
  beg = pv;
  beg->prvs = 0;
 }
  else
       if(pos->prvs == end)/// в конце
           {
             pv->p = end;
             pv->prvs = end->prvs;
            (end->prvs)->p = pv;
            end->prvs = pv;
           }
            else// в середине
          {
             pv->prvs = pos->prvs;// связываем новый элемент с предыдущим «позиции»
                     cout<<"\n111 "<<pv->prvs->d<<endl;
             pv->p = (pos->prvs)->p;/// c последующим в «позиции» элементом
                             cout<<"\n222 "<<pv->p->d<<endl;
                     /// обновляем координаты «позиции»
             (pos->prvs)->p = pv;
                      cout<<"\n333 "<<(pos->prvs)->p->d<<endl;
              ((pos->prvs)->p)->prvs = pv;
                     cout<<"\n444 "<<(pos->prvs)->p->prvs->d<<endl;
             }
f = 0;/// сбрасываем цикл while.
}
//////////////////////////////////////////
return(beg);
}

Функция поиска.
Код

order* find (order*& beg, int* nb)/// *nb – число, необходимое найти
{
order* pv = 0;
order* big = new order;/// вспомогательный список и выделение памяти под первый элемент
order* temp = 0;/// начало вспом. списка
pv = beg; 
bool f = false;
int n = 0;
/////////////////
cout<<"\n";
 while(pv)
 {
  if((pv->d)==(*nb))
          {
     f=true;
     n++;
      if(n==1)// если элемент повторился, то формируем первое поле вспом. списка
      {
        big->d = pv->d;
        big->p = 0;
        big->prvs = pv;/// данные исходника
        temp = big;// начало списка
      }
      if(n>=2)///если повторился два раза, то добавляем в вспомог. список 
          add2 (big, pv, &(pv->d));
    }
 pv = pv->p;
 }
 if(!f)
   {
     cout<<"\n Number is out!!!\n";
     exit(1);
    }
return(temp);
}


    Функция добавления в вспомогательный список:
Код

void add2 (order*& big, order*& adr, int* dg)
{
order* pv = new order;
pv->d = *dg;
pv->p = 0;
pv->prvs = adr;///данные оригинала
big->p = pv;
big = pv;
}



   Вообще функция удаления элемента или повторяющихся полей, которые были в списке изначально, работает. Я думаю, что проблема в вставки или что-то с указателем, который хранит исходный элемент. Вообщем, хз... 
   Буду благодарен за помощь! smile 

Это сообщение отредактировал(а) student0511 - 4.9.2006, 02:21

Присоединённый файл ( Кол-во скачиваний: 7 )
Присоединённый файл  order__.cpp 5,35 Kb
PM MAIL   Вверх
student0511
Дата 4.9.2006, 02:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 42
Регистрация: 26.3.2006

Репутация: нет
Всего: нет



Я думаю после комментариев код будет понятен. Извиняюсь за отсутствие онных... 
PM MAIL   Вверх
zkv
Дата 4.9.2006, 04:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата



****


Профиль
Группа: Участник Клуба
Сообщений: 2133
Регистрация: 23.7.2006
Где: Санкт-Петербург

Репутация: 26
Всего: 92



Цитата

Beg and end – как понятно из названия, являются указателями на начало и конец в исходном списке.

судя по проге это не так:
Код

    order* end = first(&temp); //здесь end->d=temp; end->p=0; end->prvs=0;
    order* beg = end;              //теперь beg указывает на end

далее при добавлении нового элемента end нацеливается на последний, а beg  как показывал на end так и показывает, в итоге end всегда указывает на последний, а beg всегда указывает на end
ИМХО твою прогу очень трудно разбирать, а проблему четко ты не указал (в итоге проще заново написать чем проверить), по этому могу помочь лишь рекомендациями: smile
далее все ИМХО, если кто то со мной не согласен буду рад выслушать smile
1. назови переменные и функции так чтобы их имена отражали свое назначение, одни только прототипы ставят в тупик:
Код

order* first (int*);
void add1 (order*&, int*);
void add2 (order*&, order*&,int*);
int display1 (order*&);
void display2 (order**);
int display3(order**);
order* find (order*&, int*);
order* delt (order*&, order*&, int*);
order* input (order*&, order*&, int*, int*);

в твоей структуре:
Код

struct order
{
int d;
order* p;
order* prvs;
};

можно лишь догадаться что prvs указывает на предыдущий элемент, про d тоже можно что то представить, про p конечно можно методом исключения предположить что это указатель на следующий, но только когда видишь имена и типы остальных членов структуры.
если же это дело обозвать так:
Код

struct order
{
  int data;
  order* prev;
  order* next;
};

то встретив выражение типа pBegin->next мы не будем ломать голову что такое next.

2. Слишком много функций, например отдельная функция добавления первого элемента, почему  бы не использовать функцию добавления элемента, а в ней сделать проверку пуст список или нет. Или такой пример:
Код

int display1 (order*& beg)
{
order* pv = beg;
int temp = pv->d;
beg = beg->p;
return (temp);
}
//////////////////////////////////////////////
void display2 (order** beg)
{
order* t = *beg;
//////////
cout<<" ";
while(t)
     cout<<display1(t)<<"\n ";
}

Зачем такие сложности? smile

3. Используй начальный отступ, прогу трудно читать

4. взглянем на 2 прототипа:
Код

int display2(order**);     //лучше int display2(const order *&) или int display2(const order &) 
find (order*&, int*);

почему, в одном из них ты передаешь указатель по ссылке, а в другом указатель на указатель? Ведь аргументы в функциях ты используешь одинаково, это просто сбивает.
или здесь, тоже хочешь "запутать врага" smile
Код

void add1 (order*&, int*);

почему бы просто не передать int по значению:
Код

void add1 (order*&, int );


ну и последнее: погоняй прогу по шагам, выводи промежуточные результаты в "подозрительных" местах, найди ошибку, и если сам не сможешь исправить (хотя это вряд ли smile )
тогда уже задавай конкретный вопрос, потому как прогу за тебя может кто и напишет, но если хочешь разобраться - делай сам. 
PM MAIL   Вверх
student0511
Дата 6.9.2006, 02:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 42
Регистрация: 26.3.2006

Репутация: нет
Всего: нет



Вообщем, проверил я пошаговой троссировкой, что творится со списком. Так вот, оказалось, что при связывании следущего после  позиции элемента с новым:  ((pos->prvs)->next)->prvs = pv  -  адреса ((pos->prvs)->next)->prvs, ((pos->prvs)->next)->prvs->prvs ... ((pos->prvs)->next)->prvs->...->prvs становятся равными. Почему я так и не понял  smile.
Функция вставки в новом виде:
Код

order* input (order*& beg, order*& end, int* nb, int* k)
{
order* pv = new order;
order* pos = find(beg, &*k);
pv->d = *nb;
bool ft = true;
/////////////////////////////////
while(pos && ft)
{
 if((pos->prvs) == beg)
 {
  pv->next = beg;
  beg->prvs = pv;
  beg = pv;
  beg->prvs = 0;
 }
  else
       if(pos->prvs == end)
         {
           pv->next = end;     
           pv->prvs = end->prvs;        
           (end->prvs)->next = pv;     
            end->prvs = pv;    
           }
        else
             {
               pv->prvs = pos->prvs;
               pv->next = (pos->prvs)->next;
               (pos->prvs)->next = pv;    
               ((pos->prvs)->next)->prvs = pv;     
             }
     ft = false;
  pos = pos->next;
 }
}
//////////////////////////////////////////
return(beg);
}

Вот результат пошаговой троссировки:

Это сообщение отредактировал(а) student0511 - 6.9.2006, 02:06

Присоединённый файл ( Кол-во скачиваний: 5 )
Присоединённый файл  buga.rar 49,47 Kb
PM MAIL   Вверх
zkv
Дата 6.9.2006, 05:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата



****


Профиль
Группа: Участник Клуба
Сообщений: 2133
Регистрация: 23.7.2006
Где: Санкт-Петербург

Репутация: 26
Всего: 92



student0511, эта функция даже не откомпилится, проверь скобки. Проясни пожалуйста, что ты передаешь в функцию в качестве аргументов (и вообще, что она должна сделать)?
Код

order* pos = find(beg, &*k);

что делает find  и что возвращает? 
&*k  - интересное выражение smile, сначала ты разыменовываешь указатель k (т.е. берешь значение из ячейки памяти, на которую он указывает), а потом вычисляешь адрес полученной ячейки, если тебе надо передать в find указатель на int, то сделай это так:
Код

order* pos = find(beg, k);

интересно, почему все-таки ты не хочешь передавать int'ы по ссылке или по значению, ведь понятнее и удобнее написать так:
Код

order* input (order*& beg, order*& end, int &nb, int k)// nb передается по ссылке, k по значению
{
//...
pv->d = nb + k;
//...
}

и еще, вижу две строчки, которые меня пугают smile
Код

               (pos->prvs)->next = pv;              //строка 1
               ((pos->prvs)->next)->prvs = pv; //строка 2    

в принципе не важно, что происходило до них, после выполнения строки 1 когда говорим (pos->prvs)->next подразумеваем pv, следовательно ((pos->prvs)->next)->prvs эквивалентно pv->prvs, а вся строка  2 эквивалентна pv->prvs = pv; может отсюда ноги у ошибки растут? smile

PS если ты передаешь beg в функцию по ссылке:
Код

order* input (order*& beg, order*& end, int* nb, int* k)

то зачем тогда еще раз его передавать в возвращаемом значении:
Код

return(beg);


Это сообщение отредактировал(а) zkv - 6.9.2006, 05:14
PM MAIL   Вверх
student0511
Дата 6.9.2006, 11:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 42
Регистрация: 26.3.2006

Репутация: нет
Всего: нет



zkv
В строчках 
Код

   (pos->prvs)->next = pv;              //строка 1
   ((pos->prvs)->next)->prvs = pv; //строка 2  
.....
ААА!!! нашёл ошибку: вернее нужно было вот как:
((pos->prvs)->next)->prvs = pv;
(pos->prvs)->next = pv;
Вот до чего доводит невнимательность.  smile  Огромное СПАСИБО, что помогли найти ошибку!!!  smile   smile 
Конечно, нужно ещё предусмотреть некоторые ситуации, но это уже проще, чем поменять местами две строчки  smile  


Это сообщение отредактировал(а) student0511 - 6.9.2006, 11:28
PM MAIL   Вверх
wnayk
Дата 19.12.2006, 19:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 12
Регистрация: 10.12.2006

Репутация: нет
Всего: нет



                                   HELP!!! smile 
У кого нибудь есть такая или похожая на эту задачка????::::
Магазин с одним продавцом.
Компьютер вместо кассового аппарата. База наличия товаров: наименование, единица измерения, цена единицы, количество, дата последнего завоза. Регистрация поступления товара( как старых ,так и новых наименований ). Оформление покупки: выписка чека, корректировка базы. Проблема уценки и описания. Инвентаризация остатков товара с вычислением суммарной стоимости. Программа должна обеспечивать диалог с помощью меню и контроль ошибок при вводе. 

PM MAIL   Вверх
JackYF
Дата 19.12.2006, 20:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


полуавантюрист
****


Профиль
Группа: Участник
Сообщений: 5814
Регистрация: 28.8.2004
Где: страна тысячи озё р

Репутация: 18
Всего: 162



wnayk, нехорошо!
Во-первых, ты уже писал данное сообщениеи тебе ответили, что сочли нужным.
Во-вторых, к этой теме оно абсолютно не относится...


--------------------
Пожаловаться на меня как модератора можно здесь.
PM MAIL Jabber   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1301 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.