将链接列表中的元音转换为开头

时间:2012-09-05 22:14:00

标签: linked-list singly-linked-list

我正在解决一个问题,其中给定一个链接的字符列表,我们必须将元音移动到开头,使得元音和辅音都按时间顺序排列。这是它们出现在原始列表中的顺序。

Input : S->T->A->C->K->O->V->E->R->F->L->O->W

Output : A->O->E->O->S->T->C->K->V->R->F->L->W

我是通过遍历列表一次创建的,创建了两个名为元音和辅音的列表,然后合并它们。

可以在不创建额外列表的情况下完成吗?我的意思是就地使用指针操作?

4 个答案:

答案 0 :(得分:1)

记住列表的开头。遇到元音后,将其移到列表的开头;元音成为你记忆中的新起点。

答案 1 :(得分:0)

1. Traverse the list
2. When you encounter a vowel, check with head if its smaller or greater
3. If smaller, re-place new vowel before head, else move head and check again
4. In the end relocate head to first

    temp = head;
    while(current.next != null) {
      if(current.isVowel()) {
        if(head.isVowel()) {
          //check the precedence
          //Re-place the current with temp
        }
        else {
          //Re-place current in front of head
        }
      }
      current = current.next;
    }

这是一种抽象的理解。正确实施。

答案 2 :(得分:0)

#include <stdio.h>
#include <string.h>
#include <ctype.h>

struct list {
    struct list *next;
    int ch;
    };
#define IS_VOWEL(p) strchr("aeiouy", tolower(p->ch))
struct list *shuffle (  struct list *lst )
{
    struct list *new=NULL, **dst, **src;
    dst = &new;
    for (src = &lst; *src; ) {
            struct list *this;
            this= *src;
            if (!IS_VOWEL(this)) { src= &(*src)->next; continue; }
            *src = this->next;
            this->next = *dst;
            *dst = this;
            dst = & (*dst)->next;
            }
    *dst = lst;
    return new;
}

int main (void)
{
    struct list arr[] = { {arr+1, 'S'} , {arr+2, 'T'} , {arr+3, 'A'}
         , {arr+4, 'C'} , {arr+5, 'K'} , {arr+6, 'O'}
         , {arr+7, 'V'} , {arr+8, 'E'} , {arr+9, 'R'}
         , {arr+10, 'F'} , {arr+11, 'L'} , {arr+12, 'O'} , {NULL, 'W'} };
    struct list *result;

    result = shuffle (arr);

    for ( ; result; result = result->next ) {
        printf( "-> %c" , result->ch );
        }
    printf( "\n" );

return 0;
}

输出:

- &GT; A-&GT; O-&GT; E-&GT; O-&GT; S-&GT; T-&GT; C-&GT; K-&GT; V-&GT; R-&GT; F-&GT; 1→ w ^

答案 3 :(得分:0)

你可以很容易地修改指针来创建两个独立的列表,而不必实际复制任何节点,这就是我所说的你想要避免创建新列表的意思。只修改原始节点中的指针。

首先让我们为列表创建结构:

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

// Structure for singly linked list.

typedef struct sNode {
    char ch;
    struct sNode *next;
} tNode;

接下来我们提供两个实用函数,第一个将一个字符附加到列表中:

// Append to list, not very efficient but debug code anyway.

static tNode *append (tNode *head, char ch) {
    // Allocate new node and populate it.

    tNode *next = malloc (sizeof (tNode));
    if (next == NULL) {
        puts ("Out of memory");
        exit (1);
    }
    next->ch = ch;
    next->next = NULL;

    // First in list, just return it.

    if (head == NULL)
        return next;

    // Else get last, adjust pointer and return head.

    tNode *this = head;
    while (this->next != NULL)
        this = this->next;
    this->next = next;
    return head;
}

第二个转储列表以进行调试:

// Debug code to dump a list.

static void dump (tNode *this) {
    if (this == NULL)
        return;
    printf ("(%08x)%c", this, this->ch);
    while ((this = this->next) != NULL)
        printf (" -> (%08x)%c", this, this->ch);
    putchar ('\n');
}

除此之外,我们需要一种简单的方法来判断一个节点是否是一个元音。出于我们的目的,我们只使用大写字母:

// Check for vowel (uppercase only here).

static int isVowel (tNode *this) {
    char ch = this->ch;
    return (ch == 'A') || (ch == 'E') || (ch == 'I')
        || (ch == 'O') || (ch == 'U');
}

现在这是重要的一点,将单个列表变成两个不同的列表(一个元音,一个辅音)。哪个列表的类型取决于列表中第一个条目的内容。

基本上做的是从列表开头的所有公共节点(本例中为“ST”)创建子列表,下一个非匹配类型的另一个子列表(“A” ),然后开始逐个处理剩余的节点,从“C”开始。

在检查每个后续节点时,调整指针以将其添加到第一个或第二个列表(同样,,而实际上不创建新节点)。一旦我们在列表的末尾达到NULL,我们就决定是否将第二个列表附加到第一个列表,反之亦然(元音必须先来)。

所有这些指针操作的代码如下所示:

// Meat of the solution, reorganise the list.

static tNode *regroup (tNode *this) {
    // No reorg on empty list.

    if (this == NULL)
        return this;

    // Find first/last of type 1 (matches head), first of type 2.

    tNode *firstTyp1 = this, *firstTyp2 = this, *lastTyp1 = this, *lastTyp2;
    while ((firstTyp2 != NULL) && (isVowel (firstTyp1) == isVowel (firstTyp2 ))) {
        lastTyp1 = firstTyp2;
        firstTyp2 = firstTyp2->next;
    }

    // No type 2 means only one type, return list as is.

    if (firstTyp2 == NULL)
        return firstTyp1;

    // Type 2 list has one entry, next node after that is for checking.

    lastTyp2 = firstTyp2;
    this = firstTyp2->next;

    //dump (firstTyp1);
    //dump (firstTyp2);
    //putchar ('\n');

    // Process nodes until list is exhausted.

    while (this != NULL) {
        // Adjust pointers to add to correct list.

        if (isVowel (this) == isVowel (lastTyp1)) {
            lastTyp2->next = this->next;
            lastTyp1->next = this;
            lastTyp1 = this;
        } else {
            lastTyp1->next = this->next;
            lastTyp2->next = this;
            lastTyp2 = this;
        }

        // Advance to next node.

        this = this->next;

        //dump (firstTyp1);
        //dump (firstTyp2);
        //putchar ('\n');
    }

    // Attach last of one list to first of the other,
    // depending on which is the vowel list.

    if (isVowel (firstTyp1)) {
        lastTyp1->next = firstTyp2;
        return firstTyp1;
    }

    lastTyp2->next = firstTyp1;
    return firstTyp2;
}

最后,没有一些描述的测试工具,没有复杂的程序是完整的,所以这里是创建并以其初始形式转储列表的东西,然后重新组织它并转储结果:

int main (void) {
    char *str = "STACKOVERFLOW";
    tNode *list = NULL;

    while (*str != '\0')
        list = append (list, *(str++));

    dump (list);
    puts("");

    list = regroup (list);
    dump (list);

    return 0;
}

进入,编译并运行所有代码后,结果如预期:

(09c03008)S -> (09c03018)T -> (09c03028)A -> (09c03038)C ->
(09c03048)K -> (09c03058)O -> (09c03068)V -> (09c03078)E ->
(09c03088)R -> (09c03098)F -> (09c030a8)L -> (09c030b8)O ->
(09c030c8)W

(09c03028)A -> (09c03058)O -> (09c03078)E -> (09c030b8)O ->
(09c03008)S -> (09c03018)T -> (09c03038)C -> (09c03048)K ->
(09c03068)V -> (09c03088)R -> (09c03098)F -> (09c030a8)L ->
(09c030c8)W

如果难以阅读,我将删除指针并按顺序列出字符:

S -> T -> A -> C -> K -> O -> V -> E -> R -> F -> L -> O -> W
A -> O -> E -> O -> S -> T -> C -> K -> V -> R -> F -> L -> W