Làm thế nào để đảo ngược một danh sách được liên kết đơn lẻ chỉ sử dụng hai con trỏ?


109

Tôi tự hỏi liệu có tồn tại một số logic để đảo ngược một danh sách được liên kết đơn lẻ chỉ sử dụng hai con trỏ hay không.

Sau đây được sử dụng để đảo ngược danh sách liên kết đơn sử dụng ba con trỏ cụ thể là 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;
}

Có bất kỳ thay thế nào khác để đảo ngược danh sách liên kết không? Đâu sẽ là logic tốt nhất để đảo ngược một danh sách được liên kết đơn lẻ, về mặt thời gian phức tạp?


1
có thể trùng lặp: stackoverflow.com/questions/818443/…
kajaco

3
Không hẳn, đó là hai hàng đợi chứ không phải là hai con trỏ.
paxdiablo

7
Vì bạn ở đây để trợ giúp chứ không phải chơi đại diện?
GManNickG

1
GMan: Đó là chuyện, tôi không chắc mình đang giúp ai, kể cả anh ta, nếu anh ta không thể theo dõi.

1
Bạn đang giúp những người trong chúng ta, những người đọc và nhận được điều gì đó từ các câu hỏi và câu trả lời. Tôi thấy nó sâu sắc.
Andrew Coleson

Câu trả lời:


133

Bất kỳ thay thế? Không, điều này rất đơn giản và không có cách nào khác về cơ bản. Thuật toán này đã là O (n) thời gian, và bạn không thể nhanh hơn thế nữa, vì bạn phải sửa đổi mọi nút.

Có vẻ như mã của bạn đang đi đúng hướng, nhưng nó không hoạt động tốt ở biểu mẫu trên. Đây là một phiên bản hoạt động:

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

Tôi không chắc về 'lỗi rõ ràng' trong bản gốc. Thiết kế khôn ngoan, không chuyển người đứng đầu trong danh sách và không trả lại người đứng đầu mới là một ý tưởng tồi. Tuy nhiên, lỗi duy nhất là dòng cuối cùng trong reverse()hàm nên được đặt đầu tiên, tôi tin. Nếu không, mã gốc hoạt động tốt khi được cắm vào bộ dây thử nghiệm gọn gàng của bạn. Bạn nhận được +1 từ tôi ngay cả khi như vậy - nhưng lời giải thích về những gì bạn coi là 'lỗi rõ ràng' sẽ cải thiện câu trả lời của bạn.
Jonathan Leffler

2
Không có lỗi trong đoạn mã trên? Bên trong vòng lặp while, bạn đang tạo một con trỏ 'tiếp theo' mới mỗi lần. Vì vậy, nếu có N nút trong danh sách liên kết, bạn đang tạo N con trỏ mới và bạn không giải phóng hoặc xóa chúng. Tôi nghĩ sẽ đúng nếu bạn tạo con trỏ 'tiếp theo' trước vòng lặp while và chỉ thực hiện phép gán 'next = root-> next' bên trong vòng lặp while.
aks 17/02/10

6
@aks: Không có rò rỉ. Chú ý malloc / etc. không được gọi nên không cần phải miễn phí. Biến 'next' được đưa vào vòng lặp, nhưng điều đó hoàn toàn ổn.

1
Ngay cả khi không bị rò rỉ, Điều cần thiết phải khai báo tiếp theo mỗi lần, như aks đã đề cập, "sẽ đúng nếu bạn tạo con trỏ 'tiếp theo' trước vòng lặp while và chỉ cần thực hiện phép gán 'next = root-> next "bên trong vòng lặp while.", phải không?
GeekyJ

1
Tôi thích các ký tự danh sách liên kết của bạn, điều đó thật gọn gàng.

43

Tôi ghét phải mang tin xấu nhưng tôi không nghĩ rằng giải pháp ba con trỏ của bạn thực sự hiệu quả. Khi tôi sử dụng nó trong khai thác thử nghiệm sau, danh sách được giảm xuống một nút, theo kết quả đầu ra sau:

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

Bạn sẽ không nhận được sự phức tạp về thời gian tốt hơn giải pháp của mình vì nó là O (n) và bạn phải truy cập vào mọi nút để thay đổi các con trỏ, nhưng bạn có thể thực hiện một giải pháp chỉ với hai con trỏ phụ khá dễ dàng, như được hiển thị trong đoạn mã sau:

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

Mã này xuất ra:

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

mà tôi nghĩ là những gì bạn đã được sau. Nó thực sự có thể làm điều này vì sau khi bạn đã tải firstvào con trỏ ngang qua danh sách, bạn có thể sử dụng lại firsttheo ý muốn.


2
Rất thanh lịch. Việc sử dụng lại firstcon trỏ trong danh sách được liên kết cho phép giải pháp chỉ sử dụng thêm 2 con trỏ, nhưng 3 con trỏ tổng vẫn cần thiết cho việc này.
Kevin Kibler

Bạn đang sử dụng đầu tiên, curNode và nxtNode, tổng cộng ba con trỏ cho việc này. tại sao đây là một giải pháp hai con trỏ?
Yashasvi

@Yash, đọc lại, hai con trỏ phụ trên đầu trang first. Cũng giống như cách giải pháp ba-con trỏ của OP có first, p, qr.
paxdiablo

@paxdiablo ơi! lỗi của tôi. Xin lỗi, tôi đã hiểu sai câu hỏi. Cảm ơn :)
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
Xin chào! Tôi biết câu hỏi này đã cũ, nhưng bạn có vui lòng giải thích những gì xảy ra trong hàm này và tại sao nó hoạt động. :) Cảm ơn!
MakeTheTrumpetsBlow

13

Đây là mã để đảo ngược một danh sách được liên kết đơn lẻ trong C .

Và ở đây nó được dán bên dưới:

// 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
Cảm ơn các nghệ thuật ASCII tuyệt vời cho việc giải thích :)
achedeuzot

3

Đúng. Tôi chắc rằng bạn có thể làm điều này giống như cách bạn có thể hoán đổi hai số mà không cần sử dụng số thứ ba . Đơn giản chỉ cần truyền con trỏ tới int / long và thực hiện thao tác XOR một vài lần. Đây là một trong những thủ thuật C tạo ra một câu hỏi vui nhộn, nhưng không có bất kỳ giá trị thực tế nào.

Bạn có thể giảm độ phức tạp O (n) không? Không thật sự lắm. Chỉ cần sử dụng danh sách liên kết kép nếu bạn nghĩ rằng bạn sẽ cần thứ tự ngược lại.


… Và vấn đề tương thích 64-bit mới được sinh ra, nếu bạn không cẩn thận. Bạn cũng không thể mua bất kỳ hiệu suất nào theo cách này.
LnxPrgr3

2
Điều này sẽ không ảnh hưởng đến sự phức tạp về thời gian - nghĩa là nó sẽ không làm cho giải pháp tốt hơn bất kỳ hơn thời gian tuyến tính. Ý tôi là, bạn có thể tiết kiệm 4 hoặc 8 byte bộ nhớ, nhưng điều đó sẽ không thay đổi độ phức tạp tổng thể của thuật toán.
poundifdef

@rascher, độ phức tạp về thời gian là phần thứ hai của câu hỏi. Phần đầu tiên phải làm với việc giảm số lượng con trỏ cần thiết.
paxdiablo

2
Tôi nghĩ rằng người đăng ban đầu đang tìm kiếm một mẹo C rẻ tiền. Theo kinh nghiệm của tôi - và tôi đã tổng hợp nó :) - các thủ thuật tránh trung gian điển hình thực sự chậm hơn so với chỉ sử dụng một bên trung gian.
Sẽ

Liên kết bị hỏng, nhưng tôi chắc chắn việc hoán đổi 2 số bằng XOR là trường học cũ :)
Dane

3

Robert Sedgewick, " Các thuật toán trong C ", Addison-Wesley, Ấn bản lần thứ 3, 1997, [Phần 3.4]

Trong trường hợp đó không phải là danh sách theo chu kỳ, do đó NULL là liên kết cuối cùng.

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

Chỉ để giải trí (mặc dù tối ưu hóa đệ quy đuôi sẽ ngăn nó ăn hết đống):


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

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

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

root = reverse(root, NULL);

2
Tôi nghĩ "nên" là nói quá lên một chút. Trình biên dịch C của bạn "có thể" thực hiện tối ưu hóa cuộc gọi đuôi và đủ dễ dàng để kiểm tra một trình biên dịch / tùy chọn nhất định cho dù nó có hay không: nhìn vào phần tháo gỡ. Hoặc cho nó một vài triệu nút và xem nếu nó bị treo ;-)
Steve Jessop

3

Để hoán đổi hai biến mà không cần sử dụng một biến tạm thời,

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

cách nhanh nhất là viết nó trong một dòng

a = a ^ b ^ (b=a)

Tương tự,

sử dụng hai hoán đổi

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

giải pháp sử dụng xor

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

giải pháp trong một dòng

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

Logic tương tự được sử dụng để đảo ngược danh sách được liên kết.

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
Điều này giả sử một int có cùng kích thước với một con trỏ, nó sẽ không hoạt động trên các hệ thống amd64 (bạn có thể sử dụng intptr_t). Mặc dù thú vị - hoán đổi theo cách này là không tối ưu trên các hệ thống hiện đại.
ideasman42

3

Bạn cần một con trỏ theo dõi sẽ theo dõi danh sách.

Bạn cần hai gợi ý:

con trỏ đầu tiên để chọn nút đầu tiên. con trỏ thứ hai để chọn nút thứ hai.

Chế biến :

Di chuyển con trỏ theo dõi

Trỏ nút thứ hai đến nút đầu tiên

Di chuyển con trỏ đầu tiên một bước, bằng cách gán con trỏ thứ hai cho một

Di chuyển con trỏ thứ hai một bước, bằng cách gán con trỏ theo dõi cho thứ hai

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

Làm thế nào về những thứ dễ đọc hơn:


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

Đây là một phiên bản đơn giản hơn trong Java. Nó chỉ sử dụng hai con trỏ 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
}

Câu hỏi đặt ra là tìm kiếm một giải pháp C, không phải là một trong Java
Degustaf

1
Câu hỏi thiên về thực hiện thao tác ngược chỉ với hai con trỏ bổ sung (hoặc tham chiếu). Cho dù C hay Java của nó thì logic đều giống nhau.
ernesto

1

Tính độ phức tạp về thời gian của thuật toán bạn đang sử dụng hiện tại và rõ ràng là nó không thể được cải thiện.


1

Tôi không hiểu tại sao cần phải trả về head khi chúng ta đang truyền nó dưới dạng đối số. Chúng tôi đang chuyển đầu danh sách liên kết sau đó chúng tôi cũng có thể cập nhật. Dưới đây là giải pháp đơn giản.

#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

Không, không có gì nhanh hơn O (n) hiện tại có thể được thực hiện. Bạn cần phải thay đổi mọi nút, vì vậy dù sao thì thời gian cũng sẽ tỷ lệ thuận với số phần tử và đó là O (n) bạn đã có.


0

Sử dụng hai con trỏ trong khi duy trì độ phức tạp thời gian là O (n), tốc độ nhanh nhất có thể đạt được, chỉ có thể thực hiện được thông qua việc ép kiểu con trỏ và hoán đổi giá trị của chúng. Đây là một triển khai:

#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

Tôi có một cách tiếp cận hơi khác. Tôi muốn sử dụng các hàm hiện có (như insert_at (chỉ mục), delete_from (chỉ mục)) để đảo ngược danh sách (giống như thao tác sang phải). Độ phức tạp vẫn là O (n) nhưng ưu điểm là mã được sử dụng lại nhiều hơn. Hãy xem phương thức another_reverse () và cho tôi biết tất cả các bạn nghĩ gì.

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

Liên hệ với tôi để thực hiện bất kỳ vấn đề C nào.
Ông Amit Kumar

0

Có, có một cách chỉ sử dụng hai con trỏ. Đó là bằng cách tạo danh sách liên kết mới trong đó nút đầu tiên là nút đầu tiên của danh sách đã cho và nút thứ hai của danh sách đầu tiên được thêm vào đầu danh sách mới, v.v.


0

Đây là phiên bản của tôi:

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

Ở đâu

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

Tôi đang sử dụng java để triển khai điều này và cách tiếp cận là phát triển theo hướng thử nghiệm do đó các trường hợp thử nghiệm cũng được đính kèm.

Lớp Node đại diện cho một nút -

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

Lớp dịch vụ lấy nút bắt đầu làm đầu vào và dự trữ nó mà không sử dụng thêm dung lượng.

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


}

Và trường hợp thử nghiệm bao gồm kịch bản trên. Xin lưu ý rằng bạn yêu cầu bình nước ép. Tôi đang sử dụng testng.jar; bạn có thể sử dụng bất kỳ thứ gì vừa ý bạn ..

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

Một thuật toán đơn giản nếu bạn sử dụng danh sách được liên kết làm cấu trúc ngăn xếp:

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

}

Hiệu suất có thể bị ảnh hưởng vì lệnh gọi hàm bổ sung tới add và malloc, vì vậy thuật toán hoán đổi địa chỉ tốt hơn nhưng thuật toán đó thực sự tạo danh sách mới để bạn có thể sử dụng các tùy chọn bổ sung như sắp xếp hoặc loại bỏ các mục nếu bạn thêm một hàm gọi lại làm tham số cho đảo ngược.


0

Đây là một cách tiếp cận hơi khác, nhưng đơn giản trong 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;
}

Đầu ra ở đây


0

Sau đây là một cách triển khai sử dụng 2 con trỏ (head và 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;
}

Thông minh và không thể giải mã được, bạn sẽ gặp rắc rối nếu sizeof(size_t) < sizeof(ListNode*)... bạn nên sử dụng std::uintptr_t.
Quentin

0

đây là một giải pháp đơn giản nhỏ ...

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

Bạn có thể có giải pháp cho vấn đề này với sự trợ giúp của chỉ một con trỏ bổ sung, con trỏ này phải tĩnh cho hàm ngược. Nó ở độ phức tạp 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

Thay vào đó, bạn có thể sử dụng đệ quy-

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

Làm thế nào là điều này chính xác. Bạn đang sử dụng nhiều hơn hai con trỏ, con trỏ chỉ ẩn trên ngăn xếp mỗi khi bạn thực hiện một lệnh gọi hàm.
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);

    }


}

nút không phải là một con trỏ, Chúng tôi chỉ đi qua đầu là nút. Hãy cho tôi biết nếu bạn cần làm rõ hơn
Raju Muke
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.