在链表中交换两个节点(不是节点的值)

时间:2015-03-23 02:52:27

标签: c linked-list nodes swap

我试图编写一个函数来按链接列表中的值交换节点。它实际上在节点不连续时有效。但是当我尝试交换连续节点时,我得到一个无限循环。如何在我的代码中解决这个特殊问题?

#include <stdio.h>
#include <stdlib.h>

/* self-referential structure */
struct listNode {
    char data; /* each listNode contains a character */
    struct listNode *nextPtr; /* pointer to next node*/
};

typedef struct listNode ListNode; /* synonym for struct listNode */
typedef ListNode *ListNodePtr; /* synonym for ListNode* */


void swap( ListNodePtr *sPtr, char value1, char value2 )
{
    ListNodePtr previousPtr1; /* pointer to previous node whose data is value1 */
    ListNodePtr currentPtr1; /* pointer to node whose data is value1 */
    ListNodePtr previousPtr2; /* pointer to previous node whose data is value2 */
    ListNodePtr currentPtr2; /* pointer to node whose data is value2 */

    previousPtr1 = NULL;
    previousPtr2 = NULL;
    currentPtr1 = *sPtr;
    currentPtr2 = *sPtr;

    /* attempt to find the node that contains value1  */
    while( currentPtr1 != NULL && currentPtr1->data != value1 ) {
        previousPtr1 = currentPtr1;
        currentPtr1 = currentPtr1->nextPtr;
    }

    /* attempt to find the node that contains value2 */
    while( currentPtr2 != NULL && currentPtr2->data != value2 ) {
        previousPtr2 = currentPtr2;
        currentPtr2 = currentPtr2->nextPtr;
    }

    if( currentPtr1 != NULL && currentPtr2 != NULL ) { /* both of the values are found */
        if( previousPtr1 == NULL ) {
            ListNodePtr tmpPtr = currentPtr1->nextPtr;
            *sPtr = currentPtr2;
            previousPtr2->nextPtr = currentPtr1;
            currentPtr1->nextPtr = currentPtr2->nextPtr;
            currentPtr2->nextPtr = tmpPtr;
        }
        else if ( previousPtr2 == NULL ) {
            ListNodePtr tmpPtr = currentPtr2->nextPtr;
            *sPtr = currentPtr1;
            previousPtr1->nextPtr = currentPtr2;
            currentPtr2->nextPtr = currentPtr1->nextPtr;
            currentPtr1->nextPtr = tmpPtr;

        }
        else {
            ListNodePtr tmpPtr = currentPtr2->nextPtr;
            previousPtr1->nextPtr = currentPtr2;
            currentPtr2->nextPtr = currentPtr1->nextPtr;
            previousPtr2->nextPtr = currentPtr1;
            currentPtr1->nextPtr = tmpPtr;
        }
    }
    else { /* at least one of the values is not found */
        printf("Not found!\n");
    }
}
int main( void )
{
    ListNodePtr startPtr = NULL; /* initially there are no nodes */
}

显然它并不是所有的主要功能,只有很少的代码可以为这个函数输入输入,还有许多其他函数,例如像这个代码中的反向函数,但我没有问题。

编辑:我不想交换节点内的值。我想交换实际的节点。

4 个答案:

答案 0 :(得分:1)

您的问题似乎因为声明不必要的变量以及使用不必要的值导致您的代码变得不必要地变得复杂而更加复杂。如果您认为您从ListNodePtr *sPtr开始,并且两个循环都基于ListNodePtr *值而发生变化,那么您可能会意识到可以使用初始化为{{的两个变量来更好地表达此算法1}},而不是四个,其中两个初始化为sPtr,另外两个NULL

*sPtr

好处是双重的:

  • 由于初始化为ListNodePtr *x = sPtr, *y = sPtr; while (*x != NULL && (*x)->data != value1) { x = &(*x)->nextPtr; } while (*y != NULL && (*y)->data != value2) { y = &(*y)->nextPtr; } 而不是sPtr,因此您无需检查以后是否有任何变量NULL(这似乎有助于模糊决定你需要交换哪些值。
  • 现在,您需要交换哪些值应该更清楚,但如果不是:交换NULL*x,交换*y(*x)->nextPtr

答案 1 :(得分:0)

找到要交换的节点的位置后,只需编写一个简单的交换例程 -

void swap(struct listNode *a,struct listNode *b)
{
  char t=a->data;
  a->data=b->data;
  b->data=t;
}

如果您按值交换节点,那么就可以从中获益。只需交换值。

现在,如果您想要交换节点 - (而不是按值)

//p-first node to be swapped
//p1-prev node of p
//r-second node to be swapped
//r1-prev node of r
// a temporay listNode *
temp=r->link;
r->link=p->link;
p->link=temp;
if(p1!=NULL)
   p1->link=r;
else
   startpointer=r;
r1->link=p;
}

答案 2 :(得分:0)

您已经在链接列表中找到了两个对应地址的值。

  if ( cur_ptr1!=NULL && cur_ptr2!=NULL){
        int  temp_val=cur_ptr1->data ; 
         cur_ptr1->data=cur_ptr2->data ;
         cur_ptr2->data = temp_val
   }

现在交换链表中的两个值。

考虑你有像

这样的节点
 |1|->|2|->|3|->|4|->|5|->|6|->NULL

现在你要交换节点2和5.然后我们可以改变像这样的值

 |1|->|5|->|3|->|4|->|2|->|6|->NULL

答案 3 :(得分:0)

你还应该考虑使用premetive迭代器而不是while循环。 生病了给你一个例子:

/**
* Macro for iterating over a list.
*
* Declares a new variable to hold each element of the list.
* Use this macro for iterating through the list conveniently.
* Note that this mcaro modifies the internal iterator.
* For example, the following code will go through a list of strings and print
* them to the standard output:
* @code
* void printList(List listOfStrings) {
*   LIST_FOREACH(char*, str, listOfStrings) {
*     printf("%s\\n", str);
*   }
* }
* @endcode

* @param type The type of the elements in the list
* @param iterator The name of the variable to hold the next list element
* @param list the list to iterate over
*/
#define LIST_FOREACH(type,iterator,list) \
for(type iterator = listGetFirst(list) ; \
    iterator ;\
    iterator = listGetNext(list))

listGetNext和listGetFirst是标准列表getter函数。 它是一个非常具有预防性的迭代器,但对于这种“重型”#34;工作,我认为这是一种足够的技术。