Замена звенья друг другом в двух-направленом связаном списке на С++

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by rudi, 5 Jul 2010.

  1. rudi

    rudi Active Member

    Joined:
    3 Jun 2010
    Messages:
    492
    Likes Received:
    186
    Reputations:
    5
    Замена звеньев друг с другом в двух-направленом связаном списке на С++

    привет.
    Допустим есть двух напрвленные связанный список
    A->B->C->D->...->Z



    и нужно менять звенья местами для сортировки
    покажите ваши варианты замены звеньев друг другом
    уже несколько часов долблюсь

    например
    чтобы могло менять местами
    A и B
    или С и Z
    Тоесть любые звенья

    [​IMG]
     
    #1 rudi, 5 Jul 2010
    Last edited: 5 Jul 2010
  2. rudi

    rudi Active Member

    Joined:
    3 Jun 2010
    Messages:
    492
    Likes Received:
    186
    Reputations:
    5
    гникто не поможет?
     
  3. greki_hoy

    greki_hoy Member

    Joined:
    4 Mar 2010
    Messages:
    326
    Likes Received:
    57
    Reputations:
    41
    самое простое
    Code:
    typedef struct _node *nodep;
    typedef void * itemp;
    
    struct _node
    {
        itemp data;
        nodep next;
        nodep prev;
    };
    
    имеем список A->B->C->D->...->Z
    тогда просто обмениваем содержимое указателей data
    Code:
    void swap_node(nodep link1, nodep link2)
    {
        itemp data;
    
        return_if_fail(link1);
        return_if_fail(link2);
    
        data = link1->data;
        link1->data = link2->data;
        link2->data = data;
    }
     
     
  4. rudi

    rudi Active Member

    Joined:
    3 Jun 2010
    Messages:
    492
    Likes Received:
    186
    Reputations:
    5
    спасибо
    но замена данных структуры местами не самое лучшее....
    данные нужно не трогать
    а лишь менять указатели
    Это так сказать увеличит скорость обработки
    да и данные у меня могут отличаться по структуре
    там у меня данные имеют в себе указатель на массив указателей, например :
    struct Box
    {
    struct Box *next;
    struct Box *prev;

    char *Quest; //Тут храниться вопрос
    char *Answ[100]; //Тут храняться ответы
    int count; //Тут храниться колл. ответов
    };


    )))))))))))
    В общем нужно менять указатели не трогая сами данные
    я уже начал писать замену указателей
    как допишу и протестирую
    выложу тут
     
    #4 rudi, 5 Jul 2010
    Last edited: 5 Jul 2010
  5. greki_hoy

    greki_hoy Member

    Joined:
    4 Mar 2010
    Messages:
    326
    Likes Received:
    57
    Reputations:
    41
    скачайте исходники GLIB там два файла glist.c
    и gslist.c реализуют одно и двух напрвленные списки

    а вообще
    Code:
    struct Box
    {
    struct Box *next;
    struct Box *prev;
    
    char *Quest; //Тут храниться вопрос
    char *Answ[100]; //Тут храняться ответы
    int count; //Тут храниться колл. ответов
    };
    
    это плохо в структуре лучше храните один указатель на данные а при таком раскладе у вас код обработки списка будет зависеть от типа данных в списке лучше сделать универсальный вот например структура нормальная
    Code:
    typedef struct _GList		GList;
    
    struct _GList
    {
      gpointer data;
      GList *next;
      GList *prev;
    };
    
    это кстати код из glib'овского списка
     
  6. rudi

    rudi Active Member

    Joined:
    3 Jun 2010
    Messages:
    492
    Likes Received:
    186
    Reputations:
    5
    Вроде сделал
    но не тестировал на все 100 %
    скорее на 80 % протестил
    тоесть полагаться на 100 низя

    сортировку связаного списка делаб пузырьковым методом
    Code:
    void __fastcall SvSp::SortLenth(void)
    {
    struct Box *ptr_n, *ptr_p;
        current = Box_first;
        bool Flag =true;
    
        while(Flag)
          {
              Flag = false;
              for(current = Box_first; current->next; current = current->next)
                 {
                      if(strlen(current->Quest) < strlen(current->next->Quest))
                          {
                            //Replace(current, current->next, Box, next, prev);
                             tmp =  current->next;
                             Replace(current, tmp, Box, next, prev);
                           current = current->prev;
                            Flag = true;
                          }
                 }
          }
    }
    

    А сама функция замены организован как макрос

    Code:
    //Заменить местами  link_1, link_2, 
    //при услови что движение замены идет слева на право
    //Например при сортировке
    #define Replace(link_1, link_2, name, next, prev) \
    do { \
           if( (link_1)->next == tmp ) \
             { \
                  if ( (link_1)->prev ) \
                     { \
                          (link_1)->prev->next = (link_2); \
                          (link_2)->prev = (link_1)->prev; \
                     } \
                   else \
                     { \
                           (link_2)->prev = NULL; \
                            name##_first = (link_2); \
                     } \
                  if( (link_2)->next ) \
                     { \
                            (link_2)->next->prev = (link_1); \
                            (link_1)->next = (link_2)->next; \
                     } \
                  else \
                     { \
                            (link_1)->next = NULL; \
                            name##_last = (link_1); \
                     } \
                  (link_1)->prev = (link_2); \
                  (link_2)->next = (link_1); \
             } \
           else \
             { \
                  (link_1)->next->prev = (link_2); \
                  (link_2)->prev->next = (link_1); \
                  if( (link_1)->prev ) \
                     { \
                         (link_1)->prev->next = (link_2); \
                          ptr_p = (link_2)->prev; \
                          (link_2)->prev = (link_1)->prev; \
                     } \
                   else \
                     { \
                          ptr_p = (link_2)->prev; \
                          (link_2)->prev = NULL; \
                          Box_first = (link_2); \
                      } \
                   if( (link_2)->next ) \
                      { \
                          (link_2)->next->prev = (link_1); \
                           ptr_n = (link_1)->next; \
                           (link_1)->next = (link_2)->next; \
                      } \
                   else  \
                      { \
                           ptr_n = (link_1)->next; \
                           (link_1)->next = NULL; \
                           Box_last = (link_1); \
                      } \
                   (link_1)->prev = ptr_p; \
                   (link_2)->next = ptr_n; \
             } \
    } while(0)
    
     
  7. Ra$cal

    Ra$cal Elder - Старейшина

    Joined:
    16 Aug 2006
    Messages:
    670
    Likes Received:
    185
    Reputations:
    78
    омг, ну макросом то зачем??? не перестаю удивляться. еще б асм вставкой сделал
     
    1 person likes this.
  8. greki_hoy

    greki_hoy Member

    Joined:
    4 Mar 2010
    Messages:
    326
    Likes Received:
    57
    Reputations:
    41
    Ra$cal
    ладно макрос от которого есть профит например реализация интрузивных списков в ядре линукса
    там всякие foreach за счет использования макросов
    тут понятно почему макрос для каждого entry
    внутри другой структуры свое смещение вычисляемое в момент компиляции тут они упрятаны в макросы а в макросе ТС код обработки списка
    одинаковый для разных типов можно спокойно в простую функцию вставить или если хочется такой же эффективности в inline функцию вот ниже пример
    где без макроса никак из за структуры самого списка
    Code:
    /**
     398 * list_for_each_entry  -       iterate over list of given type
     399 * @pos:        the type * to use as a loop cursor.
     400 * @head:       the head for your list.
     401 * @member:     the name of the list_struct within the struct.
     402 */
     403#define list_for_each_entry(pos, head, member)                          \
     404        for (pos = list_entry((head)->next, typeof(*pos), member);      \
     405             prefetch(pos->member.next), &pos->member != (head);        \
     406             pos = list_entry(pos->member.next, typeof(*pos), member))
     407
     408/**
     409 * list_for_each_entry_reverse - iterate backwards over list of given type.
     410 * @pos:        the type * to use as a loop cursor.
     411 * @head:       the head for your list.
     412 * @member:     the name of the list_struct within the struct.
     413 */
     414#define list_for_each_entry_reverse(pos, head, member)                  \
     415        for (pos = list_entry((head)->prev, typeof(*pos), member);      \
     416             prefetch(pos->member.prev), &pos->member != (head);        \
     417             pos = list_entry(pos->member.prev, typeof(*pos), member))
     418
     419/**
     420 * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue
     421 * @pos:        the type * to use as a start point
     422 * @head:       the head of the list
    
    вот пример где без макросов не обойтись сколько бы не говорили что они плохи попробуйте реализовать list_for_each_entry_reverse или list_for_each_entry без макроса :)
     
    #8 greki_hoy, 6 Jul 2010
    Last edited: 6 Jul 2010
  9. Ra$cal

    Ra$cal Elder - Старейшина

    Joined:
    16 Aug 2006
    Messages:
    670
    Likes Received:
    185
    Reputations:
    78
    std::foreach с boost::bind. Ну правда в том же бусте есть BOOST_FOREACH, но учитывая лямбды нового стандарта все будет очень просто и с обычным std::foreach без boost::bind.
    Ну и к слову - про макросы я конкретно в этом примере сказал, что они неуместны