12

私が考えることができる 1 つの方法は、リストを反転してから読み取ることです。しかし、これにはリストの変更が含まれますが、これは悪いことです。
または、リストのコピーを作成してから逆にすることもできますが、これには追加の O(n) メモリが使用されます。余分なメモリを使用せず、リストを変更せず、O(n) 時間で実行されるより良い方法はありますか

逆リンク リストのコードは、C# では次のようになります。

Void Reverse (Node head)
{
    Node prev= null;
    Node current = head;
    Node nextNode = null;

        while (current!=null)
        {
            nextNode = current.Next;
            current.Next = prev;
            prev=current;
            current = nextNode; 

        }
        head = prev;

}   

再帰的な解決策は

void ReadBackWard (Node n)
{
    if (n==null)
        return;
    else
        ReadBackward(n.Next);

    Console.WriteLine(n.Data);

}
4

13 に答える 13

11

単一リンクリストの特徴の1つは、実際には単一リンクリストであるということです。それは一方通行であり、それを他の何か(逆の単一リンクリスト、スタック、二重リンクリストなど)に変えない限り、それを克服する方法はありません。人は物事の性質に忠実でなければなりません。

先に指摘したように、リストを両方の方法でトラバースする必要がある場合。二重にリンクされたリストが必要です。それは二重にリンクされたリストの性質であり、それは双方向に行きます。

于 2009-07-12T19:51:15.113 に答える
3

O(log(n))今回はメモリとO(n log(n))時間を使用するため、マークの回答の2つのソリューションの中間を占める3番目のソリューションがあります。

これは事実上、バイナリ ツリー [ ] の逆順降下ですが、各ステップでツリー [ ]O(log(n))の最上位を見つける必要がある点が異なります。O(n)

  1. リストを 2 つに分割する
  2. リストの後半に再帰する
  3. 中点の値を出力します
  4. 前半に戻る

Pythonでの解決策は次のとおりです(C#はわかりません):

def findMidpoint(head, tail):
  pos, mid = head, head
  while pos is not tail and pos.next is not tail:
    pos, mid = pos.next.next, mid.next
  return mid

def printReversed(head, tail=None):
  if head is not tail:
    mid = findMidpoint(head, tail)
    printReversed(mid.next, tail)
    print mid.value,
    printReversed(head, mid)

これは、再帰の代わりに反復を使用して再キャストできますが、明確さが犠牲になります。

たとえば、100 万エントリのリストの場合、3 つのソリューションは次の順序になります。

ソリューション メモリ パフォーマンス
=========================================
 Marc #1 4MB 100 万回の操作
  鉱山 80B 2000 万回の操作
 Marc #2 4B 1兆オペレーション
于 2009-07-21T17:24:05.730 に答える
3
void reverse_print(node *head) 
{
    node *newHead = NULL, *cur = head;

    if(!head) return;

    // Reverse the link list O(n) time O(1) space
    while(cur){
        head = head->next;
        cur->next = newHead;
        newHead = cur;
        cur = head;
    }

    // Print the list O(n) time O(1) space
    cur = newHead;
    while(cur) {
        printf(" %d", cur->val);
        cur = cur->next;
    }

    // Reverse the link list again O(n) time O(1) space
    cur = newHead;
    while(cur){
        newHead = newHead->next;
        cur->next = head;
        head = cur;
        cur = newHead;
    }
    // Total complexity O(n) time O(1) space
}
于 2011-04-07T02:21:46.283 に答える
1

単一リンク リストが IEnumerable<T> を実装すると仮定すると、LINQ の逆拡張メソッドを利用できます。

var backwards = singlyLinkedList.Reverse();

using System.Linq;LINQ の拡張メソッドを使用するには、コード ファイルの先頭にディレクティブを追加する必要があります。

于 2009-07-20T18:19:51.303 に答える
1

スタックを作成し、すべての要素をスタックにプッシュするバリエーションは、再帰 (およびシステムの組み込みスタック) を使用することです。次の理由:

  1. それはあなたが再帰をgrokしたことを示しています
  2. コードが少なく、よりエレガントに見えます
  3. 素朴な面接担当者は、頭上にスペースがあることに気付かない場合があります (この場合は、そこで働きたいかどうかを検討することをお勧めします)。
于 2009-07-20T18:23:56.677 に答える
0

Explicit Stack プログラムで、各ノードのデータだけのスタックを作成する場合 (タイプ の Stack を作成する代わりに、タイプ の Stack<Node>を作成します<T>)、さらに良いのではないでしょうか? ノードの他の情報を保存する必要がないためです。

IEnumerable<T> Reverse (Node<T> head) {
    Stack<T> nodes = new Stack<T>();
    while(head != null) {
        nodes.Push(head.data);
        head = head.Next;
    }
    while(nodes.Count > 0) {
        yield return nodes.Pop();
    }
}
于 2016-12-22T11:37:22.467 に答える
0

これは面倒ですが、機能します:

class SinglyLinkedList {
SinglyLinkedList next;
int pos;
SinglyLinkedList(int pos) {
    this.pos = pos;
}
SinglyLinkedList previous(SinglyLinkedList startNode) {
    if (startNode == this) return null;
    if (startNode.next == this) return startNode;
    else return previous(startNode.next);
}

static int count = 0;
static SinglyLinkedList list;
static SinglyLinkedList head;
static SinglyLinkedList tail;
public static void main (String [] args) {
    init();

    System.out.println("Head: " + head.pos);
    System.out.println("Tail: " + tail.pos);

    list = head;
    System.out.print("List forwards: ");
    while (list != null) {
        System.out.print(list.pos + ",");
        list = list.next;
    }

    list = tail;
    System.out.print("\nList backwards: ");
    while (list.previous(head) != null) {
        System.out.print(list.pos + ",");
        list = list.previous(head);
    }
}
static void init() {
    list = new SinglyLinkedList(0);
    head = list;
    while (count < 100) {
        list.next = new SinglyLinkedList(++count);
        list = list.next;
    }
    tail = list;
}

}

于 2009-07-20T18:08:19.610 に答える
-1

どうしたの:

    public void printBackwards(LinkedList sl){    
        ListIterator<Element> litr = sl.listIterator(sl.size());
        Element temp;
        while(litr.previousIndex() >= 0){
            temp = litr.previous();
            System.out.println(temp);
        }
    }

O(n) のパフォーマンス、O(1) のメモリ、そしてドレミのようにシンプル!

于 2010-11-26T10:09:09.073 に答える