Yalnızca iki işaretçi kullanarak tek bağlantılı bir listeyi nasıl tersine çevirebilirim?


109

Sadece iki işaretçi kullanarak tek bağlantılı bir listeyi tersine çevirmek için bir mantık olup olmadığını merak ediyorum.

Aşağıdaki olarak üç işaretçiler kullanılarak tek bağlantılı liste ters için kullanılan p, q, r:

struct node {
    int data;
    struct node *link;
};

void reverse() {
    struct node *p = first,
                *q = NULL,
                *r;

    while (p != NULL) {
        r = q;
        q = p;
        p = p->link;
        q->link = r;
    }
    first = q;
}

Bağlantılı listeyi tersine çevirmek için başka bir alternatif var mı? Zaman karmaşıklığı açısından, tekil bağlantılı bir listeyi tersine çevirmenin en iyi mantığı nedir?



3
Pek değil, bu iki işaret yerine iki kuyruk.
paxdiablo

7
Yardım etmek için buradasın ve rep oyunu oynamadığın için mi?
GManNickG

1
GMan: Mesele bu, takip edemezse kimseye, ona bile yardım edeceğimden emin değilim.

1
Soruları ve cevapları okuyan ve onlardan bir şeyler alan bizlere yardım ediyorsunuz. Bunu anlayışlı buldum.
Andrew Coleson

Yanıtlar:


133

Herhangi bir alternatif var mı? Hayır, bu olabildiğince basit ve bunu yapmanın temelden farklı bir yolu yok. Bu algoritma zaten O (n) zamanıdır ve her düğümü değiştirmeniz gerektiğinden bundan daha hızlı olamazsınız.

Görünüşe göre kodunuz doğru yolda, ancak yukarıdaki formda tam olarak çalışmıyor. İşte çalışan bir versiyon:

#include <stdio.h>

typedef struct Node {
  char data;
  struct Node* next;
} Node;

void print_list(Node* root) {
  while (root) {
    printf("%c ", root->data);
    root = root->next;
  }
  printf("\n");
}

Node* reverse(Node* root) {
  Node* new_root = 0;
  while (root) {
    Node* next = root->next;
    root->next = new_root;
    new_root = root;
    root = next;
  }
  return new_root;
}

int main() {
  Node d = { 'd', 0 };
  Node c = { 'c', &d };
  Node b = { 'b', &c };
  Node a = { 'a', &b };

  Node* root = &a;
  print_list(root);
  root = reverse(root);
  print_list(root);

  return 0;
}

Orijinaldeki 'bariz hatalardan' emin değilim. Tasarım açısından, listenin başına geçmemek ve yeni kafayı geri vermemek kötü bir fikirdir. Yine de tek hata, reverse()fonksiyondaki son satırın önce ayarlanması gerektiğidir, inanıyorum. Aksi takdirde, orijinal kod temiz test koşumunuza takıldığında düzgün çalıştı. Benden +1 alıyorsun - ama 'bariz hatalar' olarak düşündüğün şeyin açıklaması cevabını geliştirir.
Jonathan Leffler

2
Yukarıdaki kodda bir hata yok mu? While döngüsünün içinde, her seferinde yeni bir 'sonraki' işaretçi oluşturursunuz. Dolayısıyla, bağlantılı listede N düğüm varsa, N yeni işaretçi oluşturuyorsunuz ve onları serbest bırakmıyorsunuz veya silmiyorsunuz. While döngüsünden önce 'sonraki' işaretçisini oluşturursanız ve while döngüsünün içinde 'next = root-> next' atamasını yaparsanız doğru olacağını düşünüyorum.
aks

6
@aks: Sızıntı yok. Malloc / vb. Dikkat edin. çağrılmadığından ücretsiz olmaya gerek yoktur. 'Sonraki' değişkeni, döngüye dahil edilmiştir, ancak bu tamamen sorun değildir.

1
Sızıntı olmasa bile, aks'in bahsettiği gibi, her seferinde bir sonraki bildirimde bulunmanın gerekliliği, "while döngüsünden önce 'sonraki' işaretçiyi oluşturup sadece atamayı 'next = root-> next yaparsanız doğru olur. "while döngüsünün içinde." değil mi?
GeekyJ

1
Bağlantılı liste değişmezlerini beğendim, bu harika.

43

Kötü haberlerin taşıyıcısı olmaktan nefret ediyorum ama üç işaretli çözümünüzün gerçekten işe yaradığını düşünmüyorum. Aşağıdaki test demetinde kullandığımda, liste aşağıdaki çıktıya göre bir düğüme indirildi:

==========
4
3
2
1
0
==========
4
==========

O (n) olduğu için çözümünüzden daha iyi zaman karmaşıklığı elde edemezsiniz ve işaretçileri değiştirmek için her düğümü ziyaret etmeniz gerekir, ancak aşağıdaki kodda gösterildiği gibi yalnızca iki ekstra işaretçi ile bir çözümü oldukça kolay bir şekilde yapabilirsiniz:

#include <stdio.h>

// The list element type and head.

struct node { 
    int data;
    struct node *link;
};
static struct node *first = NULL;

// A reverse function which uses only two extra pointers.

void reverse() {
    // curNode traverses the list, first is reset to empty list.
    struct node *curNode = first, *nxtNode;
    first = NULL;

    // Until no more in list, insert current before first and advance.
    while (curNode != NULL) {
        // Need to save next node since we're changing the current.
        nxtNode = curNode->link;

        // Insert at start of new list.
        curNode->link = first;
        first = curNode;

        // Advance to next.
        curNode = nxtNode;
    }
}

// Code to dump the current list.

static void dumpNodes() {
    struct node *curNode = first;
    printf ("==========\n");
    while (curNode != NULL) {
        printf ("%d\n", curNode->data);
        curNode = curNode->link;
    }
}

// Test harness main program.

int main (void) {
    int i;
    struct node *newnode;

    // Create list (using actually the same insert-before-first
    // that is used in reverse function.

    for (i = 0; i < 5; i++) {
        newnode = malloc (sizeof (struct node));
        newnode->data = i;
        newnode->link = first;
        first = newnode;
    }

    // Dump list, reverse it, then dump again.

    dumpNodes();
    reverse();
    dumpNodes();
    printf ("==========\n");

    return 0;
}

Bu kodun çıktısı:

==========
4
3
2
1
0
==========
0
1
2
3
4
==========

ki bence peşindeydin. Aslında bunu yapabilir, çünkü firstlisteyi gezen işaretçiye yükledikten sonra , istediğiniz zaman yeniden kullanabilirsiniz first.


2
Çok zarif. firstİşaretçiyi bağlantılı listenin kendisinde yeniden kullanmak, çözümün yalnızca 2 ekstra işaretçi kullanmasına izin verir , ancak bunun için yine de toplam 3 işaretçi gereklidir.
Kevin Kibler

Bunun için ilk, curNode ve nxtNode kullanıyorsunuz, toplam üç işaretçi. nasıl oluyor da bu iki işaretli bir çözüm?
Yashasvi

@Yash, tekrar oku , üstüne iki ekstra işaretçi first. OP'nin üç işaretli çözümünde olduğu firstgibi p, qve r.
paxdiablo

@paxdiablo oh! benim hatam. Üzgünüm, soruyu yanlış anladım. Teşekkürler :)
Yashasvi

25
#include <stddef.h>

typedef struct Node {
    struct Node *next;
    int data;
} Node;

Node * reverse(Node *cur) {
    Node *prev = NULL;
    while (cur) {
        Node *temp = cur;
        cur = cur->next; // advance cur
        temp->next = prev;
        prev = temp; // advance prev
    }
    return prev;
}

2
Merhaba! Bu sorunun eski olduğunu biliyorum, ancak bu işlevde ne olduğunu ve neden işe yaradığını açıklar mısınız? :) Teşekkürler!
MakeTheTrumpetsBlow

13

C'deki tek bağlantılı listeyi ters çevirmek için kod burada .

Ve burada aşağıda yapıştırılmıştır:

// reverse.c

#include <stdio.h>
#include <assert.h>

typedef struct node Node;
struct node {
    int data;
    Node *next;
};

void spec_reverse();
Node *reverse(Node *head);

int main()
{
    spec_reverse();
    return 0;
}

void print(Node *head) {
    while (head) {
        printf("[%d]->", head->data);
        head = head->next;
    }
    printf("NULL\n");
}

void spec_reverse() {
    // Create a linked list.
    // [0]->[1]->[2]->NULL
    Node node2 = {2, NULL};
    Node node1 = {1, &node2};
    Node node0 = {0, &node1};
    Node *head = &node0;

    print(head);
    head = reverse(head);
    print(head);

    assert(head == &node2);
    assert(head->next == &node1);
    assert(head->next->next == &node0);

    printf("Passed!");
}

// Step 1:
//
// prev head  next
//   |    |    |
//   v    v    v
// NULL  [0]->[1]->[2]->NULL
//
// Step 2:
//
//      prev head  next
//        |    |    |
//        v    v    v
// NULL<-[0]  [1]->[2]->NULL
//
Node *reverse(Node *head)
{
    Node *prev = NULL;
    Node *next;

    while (head) {
        next = head->next;
        head->next = prev;
        prev = head;
        head = next;
    }

    return prev;
}

4
Açıklamak için harika ASCII sanatı için teşekkürler :)
achedeuzot

3

Evet. Eminim bunu, üçüncüsünü kullanmadan iki sayıyı değiştirebildiğiniz şekilde yapabilirsiniz . İşaretçileri bir int / long'a çevirin ve XOR işlemini birkaç kez gerçekleştirin. Bu, soruları eğlenceli hale getiren, ancak pratik değeri olmayan C numaralarından biridir.

O (n) karmaşıklığını azaltabilir misiniz? Hayır gerçek değil. Ters sıraya ihtiyacınız olacağını düşünüyorsanız, çift bağlantılı bir liste kullanın.


… Ve dikkatli olmazsanız yeni bir 64-bit uyumluluk sorunu doğar. Bu şekilde de herhangi bir performans satın almanız pek olası değildir.
LnxPrgr3

2
Bu, zaman karmaşıklığını etkilemeyecek - yani çözümü doğrusal zamandan daha iyi yapmayacaktır . Demek istediğim, 4 veya 8 bayt bellek kaydedebilirsiniz, ancak bu, algoritmanın genel karmaşıklığını değiştirmez.
poundifdef

@rascher, sorunun ikinci kısmı zaman karmaşıklığıydı . İlk bölüm, gereken işaretçi sayısını azaltmakla ilgiliydi.
paxdiablo

2
Bence orijinal afiş ucuz bir C numarası arıyordu. Tecrübelerime göre - ve ben bunun profilini çıkardım :) - tipik kaçınma aracı hileleri aslında bir aracı kullanmaktan daha yavaştır.
Will

Bağlantı koptu, ama eminim ki XOR kullanarak 2 numara değiş tokuş etmek eski
Dane

3

Robert Sedgewick, " Algorithms in C ", Addison-Wesley, 3rd Edition, 1997, [Bölüm 3.4]

Döngüsel bir liste olmaması durumunda, bu nedenle NULL son bağlantıdır.

typedef struct node* link;

struct node{ int item; link next; };

/* you send the existing list to reverse() and returns the reversed one */

link reverse(link x){ link t, y = x, r = NULL; while(y != NULL){ t = y->next; y-> next = r; r = y; y = t; } return r; }


3

Sadece eğlence için (kuyruk özyineleme optimizasyonunun tüm yığını yemesini durdurmasına rağmen):


Node* reverse (Node *root, Node *end) {

    Node *next = root->next;
    root->next = end;

    return (next ? reverse(next, root) : root);
}

root = reverse(root, NULL);

2
Bence "olmalı" durumu biraz abartıyor. C derleyiciniz "kuyruk arama optimizasyonu" yapabilir ve belirli bir derleyiciyi / seçenekleri kontrol edip etmediğini kontrol etmek yeterince kolaydır: demontaj işlemine bakın. Veya ona birkaç milyon düğüm verin ve çöküp çökmediğine bakın ;-)
Steve Jessop

3

Geçici bir değişken kullanmadan iki değişkeni değiştirmek için,

a = a xor b
b = a xor b
a = a xor b

en hızlı yol, onu tek satırda yazmaktır

a = a ^ b ^ (b=a)

Benzer şekilde,

iki takas kullanmak

swap(a,b)
swap(b,c)

xor kullanarak çözüm

a = a^b^c
b = a^b^c
c = a^b^c
a = a^b^c

tek satırda çözüm

c = a ^ b ^ c ^ (a=b) ^ (b=c)
b = a ^ b ^ c ^ (c=a) ^ (a=b)
a = a ^ b ^ c ^ (b=c) ^ (c=a)

Aynı mantık, bağlantılı bir listeyi tersine çevirmek için kullanılır.

typedef struct List
{
 int info;
 struct List *next;
}List;


List* reverseList(List *head)
{
 p=head;
 q=p->next;
 p->next=NULL;
 while(q)
 {
    q = (List*) ((int)p ^ (int)q ^ (int)q->next ^ (int)(q->next=p) ^ (int)(p=q));
 }
 head = p;
 return head;
}  

1
Bu, int'in bir işaretçi ile aynı boyutta olduğunu varsayar, amd64 sistemlerinde çalışmaz (kullanabilirsiniz intptr_t). İlginç olsa da - bu şekilde değiştirmek modern sistemlerde yetersizdir.
ideasman42

3

Listeyi izleyecek bir izleme işaretçisine ihtiyacınız var .

İki işaretleyiciye ihtiyacınız var:

ilk düğümü seçmek için ilk işaretçi . ikinci düğümü seçmek için ikinci işaretçi .

İşleme :

İz İşaretçisini Taşı

İkinci düğümü ilk düğüme yöneltin

İkinci imleci bir adıma atayarak Birinci işaretçiyi bir adım hareket ettirin

İkinci işaretçiyi bir adım hareket ettirin, İz işaretçisini ikinciye atayarak

Node* reverselist( )
{
   Node *first = NULL;  // To keep first node
   Node *second = head; // To keep second node
   Node *track =  head; // Track the list

    while(track!=NULL)
    {
      track = track->next; // track point to next node;
      second->next = first; // second node point to first
      first = second; // move first node to next
      second = track; // move second node to next
    }

    track = first;

    return track;

}


2

Daha okunaklı olana ne dersiniz?


Node *pop (Node **root)
{
    Node *popped = *root;

    if (*root) {
        *root = (*root)->next;
    }

    return (popped);
}

void push (Node **root, Node *new_node)
{
    new_node->next = *root;
    *root = new_node;
}


Node *reverse (Node *root)
{
    Node *new_root = NULL;
    Node *next;

    while ((next = pop(&root))) {
        push (&new_root, next);
    }

    return (new_root);
}

2

İşte Java'nın daha basit bir sürümü. Yalnızca iki işaretçi kullanır currveprev

public void reverse(Node head) {
    Node curr = head, prev = null;

    while (head.next != null) {
        head = head.next; // move the head to next node
        curr.next = prev; //break the link to the next node and assign it to previous
        prev = curr;      // we are done with previous, move it to next node
        curr = head;      // current moves along with head
    }

    head.next = prev;     //for last node
}

Soru Java'da değil bir C çözümü arıyor
Degustaf

1
Soru daha çok ters işlemi sadece iki ek işaret (veya referans) ile yapmakla ilgilidir. İster C ister Java olsun mantık aynıdır.
ernesto

1

Şu anda kullandığınız algoritmanın zaman karmaşıklığını hesaplayın ve iyileştirilemeyeceği aşikâr olmalıdır.


1

Biz onu argüman olarak geçirirken neden başa dönmemiz gerektiğini anlamıyorum. Bağlantı listesinin başına geçiyoruz, sonra da güncelleyebiliriz. Aşağıda basit bir çözüm var.

#include<stdio.h>
#include<conio.h>

struct NODE
{
    struct NODE *next;
    int value;
};

typedef struct NODE node;

void reverse(node **head);
void add_end(node **head,int val);
void alloc(node **p);
void print_all(node *head);

void main()
{
    node *head;
    clrscr();
    head = NULL;
    add_end( &head, 1 );
    add_end( &head, 2 );
    add_end( &head, 3 );
    print_all( head );
    reverse( &head );
    print_all( head );
    getch();
}
void alloc(node **p)
{
    node *temp;
    temp = (node *) malloc( sizeof(node *) );
    temp->next = NULL;
    *p = temp;
}
void add_end(node **head,int val)
{
    node *temp,*new_node;
    alloc(&new_node);
    new_node->value = val;
    if( *head == NULL )
    {
        *head = new_node;
        return;
    }
    for(temp = *head;temp->next!=NULL;temp=temp->next);
    temp->next = new_node;
}
void print_all(node *head)
{
    node *temp;
    int index=0;
    printf ("\n\n");
    if (head == NULL)
    {
        printf (" List is Empty \n");
        return;
    }
    for (temp=head; temp != NULL; temp=temp->next,index++)
        printf (" %d ==> %d \n",index,temp->value);
}
void reverse(node **head)
{
    node *next,*new_head;
    new_head=NULL;
    while(*head != NULL)
    {
        next = (*head)->next;
        (*head)->next = new_head;
        new_head = (*head);
        (*head) = next;
    }
    (*head)=new_head;
}

1
#include <stdio.h>
#include <malloc.h>

tydef struct node
{
    int info;
    struct node *link;
} *start;

void main()
{
    rev();
}

void rev()
{
    struct node *p = start, *q = NULL, *r;
    while (p != NULL)
    {
        r = q;
        q = p;
        p = p->link;
        q->link = r;
    }

    start = q;
}

0

Hayır, mevcut O (n) 'den daha hızlı hiçbir şey yapılamaz. Her düğümü değiştirmeniz gerekir, böylece zaman zaten elemanların sayısıyla orantılı olacaktır ve bu zaten sahip olduğunuz O (n).


0

Ulaşılabilir en hızlı olan O (n) 'nin zaman karmaşıklığını korurken iki işaretçi kullanmak, yalnızca işaretçilerin sayısının belirlenmesi ve değerlerinin değiş tokuş edilmesiyle mümkün olabilir. İşte bir uygulama:

#include <stdio.h>

typedef struct node
{
    int num;
    struct node* next;
}node;

void reverse(node* head)
{
   node* ptr;
   if(!head || !head->next || !head->next->next) return;
   ptr = head->next->next;
   head->next->next = NULL;
   while(ptr)
   {
     /* Swap head->next and ptr. */
     head->next = (unsigned)(ptr =\
     (unsigned)ptr ^ (unsigned)(head->next =\
     (unsigned)head->next ^ (unsigned)ptr)) ^ (unsigned)head->next;

     /* Swap head->next->next and ptr. */
     head->next->next = (unsigned)(ptr =\
     (unsigned)ptr ^ (unsigned)(head->next->next =\
     (unsigned)head->next->next ^ (unsigned)ptr)) ^ (unsigned)head->next->next;
   }
}

void add_end(node* ptr, int n)
{
    while(ptr->next) ptr = ptr->next;
    ptr->next = malloc(sizeof(node));
    ptr->next->num = n;
    ptr->next->next = NULL;
}

void print(node* ptr)
{
    while(ptr = ptr->next) printf("%d ", ptr->num);
    putchar('\n');
}

void erase(node* ptr)
{
    node *end;
    while(ptr->next)
    {
        if(ptr->next->next) ptr = ptr->next;
        else
        {
            end = ptr->next;
            ptr->next = NULL;
            free(end);
        }
    }
}

void main()
{
    int i, n = 5;
    node* dummy_head;
    dummy_head->next = NULL;
    for(i = 1; i <= n ; ++i) add_end(dummy_head, i);
    print(dummy_head);
    reverse(dummy_head);
    print(dummy_head);
    erase(dummy_head);
}

0

Biraz farklı bir yaklaşımım var. Listeyi tersine çevirmek için mevcut işlevleri (insert_at (dizin), delete_from (dizin) gibi) kullanmak istedim (sağa kaydırma işlemi gibi bir şey). Karmaşıklık hala O (n) ama avantajı daha çok yeniden kullanılan koddur. Another_reverse () yöntemine bir göz atın ve bana ne düşündüğünüzü bildirin.

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

struct node {
    int data;
    struct node* next;
};

struct node* head = NULL;

void printList(char* msg) {
    struct node* current = head;

    printf("\n%s\n", msg);

    while (current != NULL) {
        printf("%d ", current->data);
        current = current->next;
    }
}

void insert_beginning(int data) {
    struct node* newNode = (struct node*) malloc(sizeof(struct node));

    newNode->data = data;
    newNode->next = NULL;

    if (head == NULL)
    {
        head = newNode;
    } else {
        newNode->next = head;
        head = newNode;
    }
}

void insert_at(int data, int location) {

    struct node* newNode = (struct node*) malloc(sizeof(struct node));

    newNode->data = data;
    newNode->next = NULL;

    if (head == NULL)
    {
        head = newNode;
    }

    else {
        struct node* currentNode = head;
        int index = 0;

        while (currentNode != NULL && index < (location - 1)) {
            currentNode = currentNode->next;
            index++;
        }

        if (currentNode != NULL)
        {
            if (location == 0) {
                newNode->next = currentNode;
                head = newNode;
            } else {
                newNode->next = currentNode->next;
                currentNode->next = newNode;
            }
        }
    }
}


int delete_from(int location) {

    int retValue = -1;

    if (location < 0 || head == NULL)
    {
        printf("\nList is empty or invalid index");
        return -1;
    } else {

        struct node* currentNode = head;
        int index = 0;

        while (currentNode != NULL && index < (location - 1)) {
            currentNode = currentNode->next;
            index++;
        }

        if (currentNode != NULL)
        {
            // we've reached the node just one prior to the one we want to delete

            if (location == 0) {

                if (currentNode->next == NULL)
                {
                    // this is the only node in the list
                    retValue = currentNode->data;
                    free(currentNode);
                    head = NULL;
                } else {

                    // the next node should take its place
                    struct node* nextNode = currentNode->next;
                    head = nextNode;
                    retValue = currentNode->data;
                    free(currentNode);
                }
            } // if (location == 0)
            else {
                // the next node should take its place
                struct node* nextNode = currentNode->next;
                currentNode->next = nextNode->next;

                if (nextNode != NULL
                ) {
                    retValue = nextNode->data;
                    free(nextNode);
                }
            }

        } else {
            printf("\nInvalid index");
            return -1;
        }
    }

    return retValue;
}

void another_reverse() {
    if (head == NULL)
    {
        printf("\nList is empty\n");
        return;
    } else {
        // get the tail pointer

        struct node* tailNode = head;
        int index = 0, counter = 0;

        while (tailNode->next != NULL) {
            tailNode = tailNode->next;
            index++;
        }

        // now tailNode points to the last node
        while (counter != index) {
            int data = delete_from(index);
            insert_at(data, counter);
            counter++;
        }
    }
}

int main(int argc, char** argv) {

    insert_beginning(4);
    insert_beginning(3);
    insert_beginning(2);
    insert_beginning(1);
    insert_beginning(0);

    /*  insert_at(5, 0);
     insert_at(4, 1);
     insert_at(3, 2);
     insert_at(1, 1);*/

    printList("Original List\0");

    //reverse_list();
    another_reverse();

    printList("Reversed List\0");

    /*  delete_from(2);
     delete_from(2);*/

    //printList();
    return 0;
}

0
using 2-pointers....bit large but simple and efficient

void reverse()

{

int n=0;

node *temp,*temp1;

temp=strptr;

while(temp->next!=NULL)

{

n++;      //counting no. of nodes

temp=temp->next;

}
// we will exchange ist by last.....2nd by 2nd last so.on....
int i=n/2;  

temp=strptr;

for(int j=1;j<=(n-i+1);j++)

temp=temp->next;
//  i started exchanging from in between ....so we do no have to traverse list so far //again and again for exchanging

while(i>0)

{

temp1=strptr;

for(int j=1;j<=i;j++)//this loop for traversing nodes before n/2

temp1=temp1->next;

int t;

t=temp1->info;

temp1->info=temp->info;

temp->info=t;

i--;

temp=temp->next; 

//at the end after exchanging say 2 and 4 in a 5 node list....temp will be at 5 and we will traverse temp1 to ist node and exchange ....

}

}

0
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
struct node
{
int data;
struct node *link;
};
struct node *first=NULL,*last=NULL,*next,*pre,*cur,*temp;
void create()
{
cur=(struct node*) malloc(sizeof(struct node));
printf("enter first data to insert");
scanf("%d",&cur->data);
first=last=cur;
first->link=NULL;
}
void insert()
{
int pos,c;
cur=(struct node*) malloc(sizeof(struct node));
printf("enter data to insert and also its position");
scanf("%d%d",&cur->data,&pos);
if(pos==1)
{
cur->link=first;
first=cur;
}
else
{
c=1;
    next=first;
    while(c<pos)
    {
        pre=next;
        next=next->link;
        c++;
    }
        if(pre==NULL)
        {
            printf("Invalid position");
        }
        else
        {
        cur->link=pre->link;
        pre->link=cur;
        }
}
}
void display()
{
cur=first;
while(cur!=NULL)
{
printf("data= %d\t address= %u\n",cur->data,cur);
cur=cur->link;
}
printf("\n");
}
void rev()
{
pre=NULL;
cur=first;
while(cur!=NULL)
{
next=cur->link;
cur->link=pre;
pre=cur;
cur=next;
}
first=pre;
}
void main()
{
int choice;
clrscr();
do
{
printf("Options are: -\n1:Create\n2:Insert\n3:Display\n4:Reverse\n0:Exit\n");
printf("Enter your choice: - ");
scanf("%d",&choice);
switch(choice)
{
case 1:
create();
break;
case 2:
insert();
break;
case 3:
display();
break;
case 4:
rev();
break;
case 0:
exit(0);
default:
printf("wrong choice");
}
}
while(1);
}

Herhangi bir sorunun C uygulaması için benimle iletişime geçin.
Bay Amit Kumar

0

Evet, sadece iki işaretçi kullanmanın bir yolu var. Bu, birinci düğümün verilen listenin ilk düğümü olduğu ve ilk listenin ikinci düğümünün yeni listenin başlangıcına eklendiği yeni bağlantılı liste oluşturarak yapılır.


0

İşte benim versiyonum:

void reverse(ListElem *&head)
{
    ListElem* temp;
    ListElem* elem = head->next();
    ListElem* prev = head;
    head->next(0);

    while(temp = elem->next())
    {
        elem->next(prev);
        prev = elem;
        elem = temp;
    }
    elem->next(prev);
    head = elem;
}

nerede

class ListElem{
public:
    ListElem(int val): _val(val){}
    ListElem *next() const { return _next; }
    void next(ListElem *elem) { _next = elem; }
    void val(int val){ _val = val; }
    int val() const { return _val;}
private:
    ListElem *_next;
    int _val;
};

0

Bunu uygulamak için java kullanıyorum ve yaklaşım test odaklı geliştirmedir, dolayısıyla test durumları da eklenmiştir.

Tek düğümü temsil eden Node sınıfı -

package com.adnan.linkedlist;

/**
 * User  : Adnan
 * Email : sendtoadnan@gmail.com
 * Date  : 9/21/13
 * Time  : 12:02 PM
 */
public class Node {

    public Node(int value, Node node){
        this.value = value;
        this.node = node;
    }
    private int value;
    private Node node;

    public int getValue() {
        return value;
    }

    public Node getNode() {
        return node;
    }

    public void setNode(Node node){
        this.node = node;
    }
}

Başlangıç ​​düğümünü girdi olarak alan ve fazladan boşluk kullanmadan ayıran hizmet sınıfı.

package com.adnan.linkedlist;

/**
 * User  : Adnan
 * Email : sendtoadnan@gmail.com
 * Date  : 9/21/13
 * Time  : 11:54 AM
 */
public class SinglyLinkedListReversal {

    private static final SinglyLinkedListReversal service 
= new SinglyLinkedListReversal();
    public static SinglyLinkedListReversal getService(){
        return service;
    }



    public Node reverse(Node start){
        if (hasOnlyNodeInLinkedList(start)){
            return start;
        }
        Node firstNode, secondNode, thirdNode;
        firstNode = start;
        secondNode = firstNode.getNode();
        while (secondNode != null ){
            thirdNode = secondNode.getNode();
            secondNode.setNode(firstNode);
            firstNode = secondNode;
            secondNode = thirdNode;
        }
        start.setNode(null);
        return firstNode;
    }

    private boolean hasOnlyNodeInLinkedList(Node start) {
        return start.getNode() == null;
    }


}

Ve yukarıdaki senaryoyu kapsayan test durumu. Lütfen hurda kavanozlarına ihtiyacınız olduğunu unutmayın. Testng.jar kullanıyorum; sizi memnun eden her şeyi kullanabilirsiniz ..

package com.adnan.linkedlist;

import org.testng.annotations.Test;

import static org.testng.AssertJUnit.assertTrue;

/**
 * User  : Adnan
 * Email : sendtoadnan@gmail.com
 * Date  : 9/21/13
 * Time  : 12:11 PM
 */
public class SinglyLinkedListReversalTest {

    private SinglyLinkedListReversal reversalService = 
SinglyLinkedListReversal.getService();

    @Test
    public void test_reverseSingleElement() throws Exception {
        Node node = new Node(1, null);
        reversalService.reverse(node);
        assertTrue(node.getNode() == null);
        assertTrue(node.getValue() == 1);
    }


    //original - Node1(1) -> Node2(2) -> Node3(3)
    //reverse - Node3(3) -> Node2(2) -> Node1(1)
    @Test
    public void test_reverseThreeElement() throws Exception {
        Node node3 = new Node(3, null);
        Node node2 = new Node(2, node3);
        Node start = new Node(1, node2);


        start = reversalService.reverse(start);
        Node test = start;
        for (int i = 3; i >=1 ; i -- ){
          assertTrue(test.getValue() == i);
            test = test.getNode();
        }


    }

    @Test
    public void test_reverseFourElement() throws Exception {
        Node node4 = new Node(4, null);
        Node node3 = new Node(3, node4);
        Node node2 = new Node(2, node3);
        Node start = new Node(1, node2);


        start = reversalService.reverse(start);
        Node test = start;
        for (int i = 4; i >=1 ; i -- ){
            assertTrue(test.getValue() == i);
            test = test.getNode();
        }
    }

        @Test
        public void test_reverse10Element() throws Exception {
            Node node10 = new Node(10, null);
            Node node9 = new Node(9, node10);
            Node node8 = new Node(8, node9);
            Node node7 = new Node(7, node8);
            Node node6 = new Node(6, node7);
            Node node5 = new Node(5, node6);
            Node node4 = new Node(4, node5);
            Node node3 = new Node(3, node4);
            Node node2 = new Node(2, node3);
            Node start = new Node(1, node2);


            start = reversalService.reverse(start);
            Node test = start;
            for (int i = 10; i >=1 ; i -- ){
                assertTrue(test.getValue() == i);
                test = test.getNode();
            }


    }

    @Test
    public void test_reverseTwoElement() throws Exception {
        Node node2 = new Node(2, null);
        Node start = new Node(1, node2);


        start = reversalService.reverse(start);
        Node test = start;
        for (int i = 2; i >=1 ; i -- ){
            assertTrue(test.getValue() == i);
            test = test.getNode();
        }


    }
}

0

Bağlantılı listeyi yığın yapısı olarak kullanırsanız basit bir algoritma:

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

typedef struct list {
    int key;
    char value;
    struct list* next;
} list;
void print(list*);
void add(list**, int, char);
void reverse(list**);
void deleteList(list*);

int main(void) {
    list* head = NULL;
    int i=0;
    while ( i++ < 26 ) add(&head, i, i+'a');
    printf("Before reverse: \n");
    print(head);
    printf("After reverse: \n");
    reverse(&head);
    print(head);
    deleteList(head);

}
void deleteList(list* l) {

    list* t = l;    
    while ( t != NULL ) {
        list* tmp = t;
        t = t->next;
        free(tmp);
    }

}
void print(list* l) {
    list* t = l;
    while ( t != NULL) {
        printf("%d:%c\n", t->key, t->value);
        t = t->next;
    }
}

void reverse(list** head) {
    list* tmp = *head;
    list* reversed = NULL;
    while ( tmp != NULL ) {
        add(&reversed, tmp->key, tmp->value);
        tmp = tmp->next;
    }
    deleteList(*head);
    *head = reversed;
}

void add(list** head, int k, char v) {

    list* t = calloc(1, sizeof(list));
    t->key = k; t->value = v;
    t->next = *head;
    *head = t;

}

Add ve malloc'a ek işlev çağrısı nedeniyle performans etkilenebilir, bu nedenle adres değiş tokuşlarının algoritmaları daha iyidir, ancak bu gerçekten yeni bir liste oluşturur; tersine çevirmek.


0

İşte C ++ 11'de biraz farklı ama basit bir yaklaşım:

#include <iostream>

struct Node{
    Node(): next(NULL){}
    Node *next;
    std::string data;
};

void printlist(Node* l){
    while(l){
        std::cout<<l->data<<std::endl;
        l = l->next;
    }
    std::cout<<"----"<<std::endl;
}

void reverse(Node*& l)
{
    Node* prev = NULL;
    while(l){
        auto next = l->next;
        l->next = prev;
        prev=l;
        l=next;
    }
    l = prev;
}

int main() {
    Node s,t,u,v;
    s.data = "1";
    t.data = "2";
    u.data = "3";
    v.data = "4";
    s.next = &t;
    t.next = &u;
    u.next = &v;
    Node* ptr = &s;
    printlist(ptr);
    reverse(ptr);
    printlist(ptr);
    return 0;
}

Buradan çıktı alın


0

Aşağıda 2 işaretçi kullanan bir uygulama yer almaktadır (baş ve r)

ListNode * reverse(ListNode* head) {

    ListNode *r = NULL;

    if(head) {
        r = head->next;
        head->next = NULL;
    }

    while(r) {
        head = reinterpret_cast<ListNode*>(size_t(head) ^ size_t(r->next));
        r->next = reinterpret_cast<ListNode*>(size_t(r->next) ^ size_t(head));
        head = reinterpret_cast<ListNode*>(size_t(head) ^ size_t(r->next));

        head = reinterpret_cast<ListNode*>(size_t(head) ^ size_t(r));
        r = reinterpret_cast<ListNode*>(size_t(r) ^ size_t(head));
        head = reinterpret_cast<ListNode*>(size_t(head) ^ size_t(r));
    }
    return head;
}

Ne kadar zeki ve çözülemez olsa da, eğer sizeof(size_t) < sizeof(ListNode*)kullanman gerekiyorsa başın belada std::uintptr_t.
Quentin

0

işte biraz basit bir çözüm ...

void reverse()
{
    node * pointer1 = head->next;
    if(pointer1 != NULL)
    {
        node *pointer2 = pointer1->next;
        pointer1->next = head;
        head->next = NULL;
        head = pointer1;

        if(pointer2 != NULL)
        {

            while(pointer2 != NULL)
            {
                pointer1 = pointer2;
                pointer2 = pointer2->next;
                pointer1->next = head;
                head = pointer1;
            }

            pointer1->next = head;
            head = pointer1;
        }       
   }
 }

0

Ters fonksiyon için statik olması gereken fazladan bir işaretçi yardımıyla bu sorunun çözümüne sahip olabilirsiniz. O (n) karmaşıklığı içinde.

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

typedef struct List* List;
struct List {
   int val;
   List next;
};

List reverse(List list) { /* with recursion and one static variable*/
    static List tail;
    if(!list || !list->next) {
        tail = list;

        return tail;
    } else {
        reverse1(list->next);
        list->next->next = list;
        list->next = NULL;

        return tail;
    }
}

0

Alternatif olarak, özyinelemeyi kullanabilirsiniz.

struct node* reverseList(struct node *head)
{
    if(head == NULL) return NULL;
    if(head->next == NULL) return head;

    struct node* second = head->next;       
    head->next = NULL;

    struct node* remaining = reverseList(second);
    second->next = head;

    return remaining;
}

Bu nasıl doğru? İkiden fazla işaretçi kullanıyorsunuz, sadece bir işlev çağrısı yaptığınızda yığın üzerinde gizlidir.
Mike G

0
curr = head;
prev = NULL;

while (curr != NULL) {
    next = curr->next; // store current's next, since it will be overwritten
    curr->next = prev;
    prev = curr;
    curr = next;
}

head = prev; // update head

0
class Node {
    Node next;
    int data;

    Node(int item) {
        data = item;
        next = null;
    }
}

public class LinkedList {

    static Node head;

    //Print LinkedList
    public static void printList(Node node){

        while(node!=null){
            System.out.print(node.data+" ");
            node = node.next;
        }
        System.out.println();
    }

    //Reverse the LinkedList Utility
    public static Node reverse(Node node){

        Node new_node = null;

        while(node!=null){

            Node next = node.next;
            node.next = new_node;
            new_node = node;
            node = next;

        }
        return new_node;
    }

    public static void main(String[] args) {

        //Creating LinkedList
        LinkedList.head = new Node(1);
        LinkedList.head.next = new Node(2);
        LinkedList.head.next.next = new Node(3);
        LinkedList.head.next.next.next = new Node(4);

        LinkedList.printList(LinkedList.head);

        Node node = LinkedList.reverse(LinkedList.head);

        LinkedList.printList(node);

    }


}

node bir işaretçi değildir, biz sadece node olarak kafa geçtik. Daha fazla açıklamaya ihtiyacınız olursa haberim olsun
Raju Muke
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.