Bagaimana cara membalikkan daftar tertaut tunggal dengan hanya menggunakan dua petunjuk?


109

Saya ingin tahu apakah ada logika untuk membalikkan daftar tertaut tunggal dengan hanya menggunakan dua petunjuk.

Berikut ini digunakan untuk membalikkan linked list tunggal dengan menggunakan tiga pointer yaitu 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;
}

Apakah ada alternatif lain untuk membalikkan daftar tertaut? Apa logika terbaik untuk membalikkan daftar tertaut tunggal, dalam hal kerumitan waktu?



3
Tidak juga, itu dua antrian, bukan dua petunjuk.
paxdiablo

7
Karena Anda di sini untuk membantu, dan tidak memainkan permainan rep?
GManNickG

1
GMan: Itu masalahnya, saya tidak yakin saya membantu siapa pun, bahkan dia, jika dia tidak bisa menindaklanjuti.

1
Anda membantu kami yang membaca dan mendapatkan sesuatu dari pertanyaan dan jawaban. Saya merasa itu berwawasan.
Andrew Coleson

Jawaban:


133

Ada alternatif lain? Tidak, ini sesederhana mungkin, dan tidak ada cara yang berbeda secara fundamental untuk melakukannya. Algoritma ini sudah O (n) waktu, dan Anda tidak bisa lebih cepat dari itu, karena Anda harus memodifikasi setiap node.

Sepertinya kode Anda ada di jalur yang benar, tetapi tidak berfungsi dengan baik di formulir di atas. Ini versi yang berfungsi:

#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;
}

Saya tidak yakin tentang 'kesalahan yang jelas' dalam aslinya. Dari segi desain, tidak memasukkan kepala daftar dan tidak mengembalikan kepala baru adalah ide yang buruk. Satu-satunya bug, bagaimanapun, adalah baris terakhir dalam reverse()fungsi yang harus disetel terlebih dahulu, saya yakin. Jika tidak, kode asli berfungsi dengan baik saat dicolokkan ke harnes uji yang rapi. Meskipun demikian, Anda mendapatkan +1 dari saya - tetapi penjelasan tentang apa yang Anda anggap sebagai 'kesalahan yang nyata' akan meningkatkan jawaban Anda.
Jonathan Leffler

2
Apakah tidak ada bug pada kode di atas? Di dalam while loop, Anda membuat penunjuk 'berikutnya' baru setiap kali. Jadi jika ada N node dalam daftar tertaut, Anda membuat N penunjuk baru dan Anda tidak membebaskan atau menghapusnya. Saya pikir itu akan benar jika Anda membuat pointer 'berikutnya' sebelum loop sementara dan hanya membuat tugas 'next = root-> next' di dalam loop sementara.
aks

6
@aks: Tidak ada kebocoran. Perhatikan malloc / etc. tidak dipanggil jadi tidak perlu gratis. Variabel 'next' memiliki cakupan ke loop, tapi itu tidak masalah.

1
Bahkan jika tidak ada kebocoran, Apa perlunya mendeklarasikan next setiap kali, seperti yang disebutkan aks, "akan benar jika Anda membuat penunjuk 'berikutnya' sebelum loop sementara dan hanya membuat tugas 'next = root-> next 'di dalam while loop. ", bukan?
GeekyJ

1
Saya suka literal daftar tertaut Anda, itu rapi.

43

Saya benci menjadi pembawa berita buruk, tetapi menurut saya solusi tiga petunjuk Anda tidak benar-benar berfungsi. Ketika saya menggunakannya di harness tes berikut, daftarnya dikurangi menjadi satu node, sesuai output berikut:

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

Anda tidak akan mendapatkan kerumitan waktu yang lebih baik daripada solusi Anda karena ini adalah O (n) dan Anda harus mengunjungi setiap node untuk mengubah pointer, tetapi Anda dapat melakukan solusi hanya dengan dua pointer tambahan dengan mudah, seperti yang ditunjukkan pada kode berikut:

#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;
}

Kode ini menghasilkan:

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

yang menurut saya adalah apa yang Anda kejar. Ini benar-benar dapat melakukan ini karena, setelah Anda memuat firstke penunjuk yang melintasi daftar, Anda dapat menggunakan kembali firstsesuka hati.


2
Sangat elegan. Menggunakan kembali firstpenunjuk pada daftar tertaut itu sendiri memungkinkan solusi untuk menggunakan hanya 2 penunjuk tambahan , tetapi 3 penunjuk total masih diperlukan untuk ini.
Kevin Kibler

Anda menggunakan pertama, curNode dan nxtNode, total tiga petunjuk untuk ini. kenapa ini adalah solusi dua penunjuk?
Yashasvi

@Yash, baca lagi, dua petunjuk tambahan di atas first. Dengan cara yang sama solusi tiga-pointer OP memiliki first, p, qdan r.
paxdiablo

@paxdiablo oh! salahku. Maaf, saya salah paham dengan pertanyaan itu. Terima kasih :)
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
Halo! Saya tahu pertanyaan ini sudah lama, tetapi maukah Anda menjelaskan apa yang terjadi dalam fungsi ini, dan mengapa ini berhasil. :) Terima kasih!
MakeTheTrumpetsBlow

13

Berikut kode untuk membalikkan daftar sendiri-sendiri terkait dalam C .

Dan di sini ditempel di bawah ini:

// 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
Terima kasih untuk seni ASCII yang luar biasa karena telah menjelaskan :)
achedeuzot

3

Iya. Saya yakin Anda dapat melakukan ini dengan cara yang sama Anda dapat menukar dua nomor tanpa menggunakan yang ketiga . Cukup lemparkan pointer ke int / long dan lakukan operasi XOR beberapa kali. Ini adalah salah satu trik C yang membuat pertanyaan menyenangkan, tetapi tidak memiliki nilai praktis.

Bisakah Anda mengurangi kompleksitas O (n)? Tidak terlalu. Cukup gunakan daftar tertaut ganda jika Anda merasa perlu urutan terbalik.


… Dan masalah kompatibilitas 64-bit baru muncul, jika Anda tidak berhati-hati. Anda juga tidak mungkin membeli kinerja apa pun dengan cara ini.
LnxPrgr3

2
Ini tidak akan mempengaruhi kompleksitas waktu - artinya, ini tidak akan membuat solusi lebih baik dari waktu linier. Maksud saya, Anda mungkin menghemat 4 atau 8 byte memori, tetapi itu tidak akan mengubah keseluruhan kompleksitas algoritme.
poundifdef

@rascher, kompleksitas waktu adalah bagian kedua dari pertanyaan tersebut. Bagian pertama harus dilakukan dengan mengurangi jumlah petunjuk yang diperlukan.
paxdiablo

2
Saya pikir poster asli sedang mencari trik C murah. Dalam pengalaman saya - dan saya telah membuat profilnya :) - trik perantara menghindari yang khas sebenarnya lebih lambat daripada hanya menggunakan perantara.
Akankah

Tautan rusak, tapi saya yakin menukar 2 nomor menggunakan XOR adalah jadul :)
Dane

3

Robert Sedgewick, " Algorithms in C ", Addison-Wesley, Edisi ke-3, 1997, [Bagian 3.4]

Jika itu bukan daftar siklik, maka NULL adalah tautan terakhir.

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

Hanya untuk bersenang-senang (meskipun pengoptimalan rekursi ekor harus menghentikannya memakan semua tumpukan):


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

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

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

root = reverse(root, NULL);

2
Saya pikir "harus" sedikit melebih-lebihkan kasus ini. Compiler C Anda "mungkin" melakukan optimasi tail-call, dan cukup mudah untuk memeriksa kompiler / opsi tertentu apakah benar atau tidak: lihat pembongkaran. Atau berikan beberapa juta node dan lihat apakah itu macet ;-)
Steve Jessop

3

Untuk menukar dua variabel tanpa menggunakan variabel sementara,

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

cara tercepat adalah dengan menuliskannya dalam satu baris

a = a ^ b ^ (b=a)

Demikian pula,

menggunakan dua swap

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

solusi menggunakan xor

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

solusi dalam satu baris

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

Logika yang sama digunakan untuk membalik daftar tertaut.

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
Ini mengasumsikan int memiliki ukuran yang sama dengan pointer, itu tidak akan berfungsi pada sistem amd64 (Anda dapat menggunakan intptr_t). Meskipun menarik - menukar cara ini kurang optimal pada sistem modern.
ideasman42

3

Anda membutuhkan penunjuk trek yang akan melacak daftar.

Anda membutuhkan dua petunjuk:

penunjuk pertama untuk memilih simpul pertama. pointer kedua untuk memilih node kedua.

Pengolahan:

Pindahkan Track Pointer

Arahkan simpul kedua ke simpul pertama

Pindahkan penunjuk pertama satu langkah, dengan menetapkan penunjuk kedua ke satu

Pindahkan penunjuk kedua satu langkah, Dengan menetapkan penunjuk Lacak ke kedua

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

Bagaimana kalau lebih mudah dibaca:


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

Ini adalah versi yang lebih sederhana di Java. Itu hanya menggunakan dua petunjuk curr&prev

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
}

Pertanyaannya adalah mencari solusi C, bukan di Jawa
Degustaf

1
Pertanyaannya lebih banyak tentang melakukan operasi kebalikan dengan hanya dua petunjuk tambahan (atau referensi). Apakah itu C atau Java, logikanya sama.
ernesto

1

Cari tahu kerumitan waktu dari algoritme yang Anda gunakan sekarang dan harus jelas terlihat bahwa algoritme tersebut tidak dapat ditingkatkan.


1

Saya tidak mengerti mengapa ada kebutuhan untuk kembali ke kepala saat kami menyampaikannya sebagai argumen. Kami melewati kepala daftar tautan kemudian kami dapat memperbarui juga. Di bawah ini adalah solusi sederhana.

#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

Tidak, tidak ada yang lebih cepat dari O (n) saat ini yang dapat dilakukan. Anda perlu mengubah setiap node, jadi waktu akan proporsional dengan jumlah elemen dan itulah O (n) yang sudah Anda miliki.


0

Menggunakan dua pointer sambil mempertahankan kompleksitas waktu O (n), yang paling cepat dicapai, mungkin hanya dapat dilakukan melalui jumlah casting pointer dan menukar nilainya. Berikut implementasinya:

#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

Saya memiliki pendekatan yang sedikit berbeda. Saya ingin menggunakan fungsi yang ada (seperti insert_at (index), delete_from (index)) untuk membalikkan daftar (seperti operasi shift kanan). Kompleksitasnya masih O (n) tetapi keuntungannya adalah kode yang lebih banyak digunakan kembali. Lihat metode another_reverse () dan beri tahu saya pendapat Anda semua.

#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);
}

Hubungi saya untuk implementasi C masalah apa pun.
Tn. Amit Kumar

0

Ya, ada cara yang hanya menggunakan dua petunjuk. Yaitu dengan membuat daftar tertaut baru di mana simpul pertama adalah simpul pertama dari daftar yang diberikan dan simpul kedua dari daftar pertama ditambahkan pada awal daftar baru dan seterusnya.


0

Ini versi saya:

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;
}

dimana

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

Saya menggunakan java untuk mengimplementasikan ini dan pendekatannya adalah pengembangan yang digerakkan oleh uji sehingga kasus uji juga dilampirkan.

Kelas Node yang mewakili node tunggal -

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;
    }
}

Kelas layanan yang mengambil node awal sebagai masukan dan memesannya tanpa menggunakan ruang ekstra.

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;
    }


}

Dan kasus uji yang mencakup skenario di atas. Harap dicatat bahwa Anda memerlukan stoples junit. Saya menggunakan testng.jar; Anda dapat menggunakan apapun yang Anda suka ..

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

Algoritme sederhana jika Anda menggunakan daftar tertaut sebagai struktur tumpukan:

 #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;

}

Kinerja mungkin terpengaruh karena pemanggilan fungsi tambahan ke add dan malloc sehingga algoritme pertukaran alamat lebih baik tetapi yang sebenarnya membuat daftar baru sehingga Anda dapat menggunakan opsi tambahan seperti mengurutkan atau menghapus item jika Anda menambahkan fungsi panggilan balik sebagai parameter ke balik.


0

Berikut ini adalah pendekatan yang sedikit berbeda, tetapi sederhana di C ++ 11:

#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;
}

Keluarkan di sini


0

Berikut ini adalah salah satu implementasi menggunakan 2 pointer (head dan 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;
}

Sepintar dan tidak terbaca seperti itu, Anda dalam masalah jika sizeof(size_t) < sizeof(ListNode*)... Anda harus menggunakannya std::uintptr_t.
Quentin

0

berikut ini sedikit solusi sederhana ...

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

Anda dapat memiliki solusi untuk masalah ini dengan bantuan hanya satu penunjuk tambahan, yang harus statis untuk fungsi sebaliknya. Ini dalam kompleksitas O (n).

#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

Sebagai alternatif, Anda dapat menggunakan rekursi-

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;
}

Bagaimana ini benar. Anda menggunakan lebih dari dua pointer, hanya tersembunyi di stack setiap kali Anda melakukan panggilan fungsi.
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 bukan pointer, Kami baru saja melewatkan head sebagai node. Beri tahu saya jika Anda membutuhkan klarifikasi lebih lanjut
Raju Muke
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.