zoukankan      html  css  js  c++  java
  • 将单链表翻转的两种方法

    单链表翻转很容易理解,例如:

    输入: NODE1->NODE2->NODE3->NODE4->NODE5->NULL

    输出: NODE5->NODE4->NODE3->NODE2->NODE1->NULL

    那么,定义单链表如下: (为简单起见,将data字段定义为int, 当然实际应用中data很可能是一个复杂的结构体)

    typedef struct list_s {
            int data;
            struct list_s *next;
    } list_t;

    如何将单链表翻转,有如下两种方法。

    1. 使用N个辅助存储空间aux[],N为单链表中所有结点的个数。将所有结点的地址反向存入aux[]中,然后根据aux[]重新生成一个单链表。
    2. 只使用2个辅助存储空间,从头到尾遍历单链表并翻转。

    其中,方法1使用了较多的辅助存储空间,但实现起来很简单,借助了栈(stack)的思想。 跟方法1比起来,方法2的时间效率和空间效率都要更胜一筹,不过实现起来难度稍大一点。

    方法1的代码实现如下:

    o foo1.c

     1 static int get_length(list_t *head)
     2 {
     3         int len = 0;
     4         for (list_t *p = head; p != NULL; p = p->next)
     5                 len++;
     6         return len;
     7 }
     8 
     9 void reverse_singly_linked_list(list_t **head)
    10 {
    11         if (*head == NULL)
    12                 return;
    13 
    14         int len = get_length(*head);
    15         if (len < 2)
    16                 return;
    17 
    18         list_t **aux = (list_t **)malloc(sizeof (list_t *) * len);
    19         if (aux == NULL) /* error */
    20                 return;
    21 
    22         /* save addr of per node to aux[] */
    23         int index = 0;
    24         for (list_t *p = *head; p != NULL; p = p->next) {
    25                 aux[len-1-index] = p;
    26                 index++;
    27         }
    28 
    29         /* rebuild the singly linked list by walking aux[] */
    30         *head = aux[0];
    31         for (int i = 0; i < len-1; i++)
    32                 aux[i]->next = aux[i+1];
    33         aux[len-1]->next = NULL;
    34 
    35         free(aux);
    36 }

    方法2的代码实现如下:

    o foo2.c

     1 void reverse_singly_linked_list(list_t **head)
     2 {
     3         list_t *newhead = NULL;
     4         list_t *this = *head;
     5         list_t *prev = NULL;
     6 
     7         while (this != NULL) {
     8                 /*
     9                  * If this->next is NULL, this is the tail node, which should
    10                  * be the new head
    11                  */
    12                 if (this->next == NULL)
    13                         newhead = this;
    14 
    15                 /*
    16                  * ListIn:  prevNode -> thisNode -> nextNode
    17                  * ListOut: prevNode <- thisNode <- nextNode
    18                  *          1. thisNode->next = prevNode;
    19                  *          2.       prevNode = thisNode;
    20                  *          3.       thisNode = thisNode->next;
    21                  */
    22                 list_t *next = this->next; /* a. save the next */
    23                 this->next = prev;         /* b. reverse */
    24                 prev = this;               /* c. move prev forward */
    25                 this = next;               /* d. move this forward */
    26         }
    27 
    28         *head = newhead;
    29 }

    用meld diff foo1.c foo2.c截图如下:

    完整的C代码点这里

    最后,对单链表翻转函数做单元测试需要考虑三种情况:

    • 输入的单链表头结点指针为NULL
    • 输入的单链表只有一个结点
    • 输入的单链表包含多个结点
  • 相关阅读:
    Elementary Methods in Number Theory Exercise 1.2.25
    Elementary Methods in Number Theory Exercise 1.2.14
    图解欧几里德算法
    图解欧几里德算法
    Elementary Methods in Number Theory Exercise 1.2.14
    Android中的长度单位详解(dp、sp、px、in、pt、mm)
    分享下多年积累的对JAVA程序员成长之路的总结
    android异常之都是deamon惹的祸The connection to adb is down, and a severe error has occured.
    TomatoCartv1.1.8.2部署时报错
    JavaScript浏览器对象之二Document对象
  • 原文地址:https://www.cnblogs.com/idorax/p/6717817.html
Copyright © 2011-2022 走看看