Как определить, имеет ли связанный список цикл с помощью только двух ячеек памяти

Вы можете использовать AnimationController для управления продолжительностью анимации.

Чтобы нарисовать линию «шаг за шагом», вы можете использовать Tween (линейная интерполяция между начальным и конечным значением).

Тогда вам просто нужно передать текущий прогресс своему рисователю и вычислить новую ширину / высоту для каждого paint() при вызове canvas.drawLine.

Рабочий пример:

import 'package:flutter/material.dart';

class Line extends StatefulWidget {
  @override
  State createState() => _LineState();
}

class _LineState extends State with SingleTickerProviderStateMixin {
  double _progress = 0.0;
  Animation animation;

  @override
  void initState() {
    super.initState();
    var controller = AnimationController(duration: Duration(milliseconds: 3000), vsync: this);

    animation = Tween(begin: 1.0, end: 0.0).animate(controller)
      ..addListener(() {
        setState(() {
          _progress = animation.value;
        });
      });

    controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return CustomPaint(painter: LinePainter(_progress));
  }
}

class LinePainter extends CustomPainter {
  Paint _paint;
  double _progress;

  LinePainter(this._progress) {
    _paint = Paint()
      ..color = Colors.green
      ..strokeWidth = 8.0;
  }

  @override
  void paint(Canvas canvas, Size size) {
    canvas.drawLine(Offset(0.0, 0.0), Offset(size.width - size.width * _progress, size.height - size.height * _progress), _paint);
  }

  @override
  bool shouldRepaint(LinePainter oldDelegate) {
    return oldDelegate._progress != _progress;
  }
}

Затем используйте его следующим образом:

import 'package:flutter/material.dart';

class Home extends StatefulWidget {
  @override
  State createState() {
    return _HomeState();
  }
}

class _HomeState extends State {
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: AppBar(
        title: Text('Line animation'),
        leading: new Icon(Icons.insert_emoticon),
      ),
      backgroundColor: Colors.white,
      body: SizedBox(height: 200, width: 200, child: Line()),
    );
  }
}

Линия будет проведена в поле размера от 0,0 до 200,200 через 3 секунды .

Результат:

enter image description here

44
задан Bill the Lizard 15 September 2012 в 23:19
поделиться

4 ответа

Я предложил бы использовать Floyd's Cycle-Finding Algorithm иначе Tortoise and the Hare Algorithm. Это имеет O (n) сложность, и я думаю, что это соответствует Вашим требованиям.

Пример кода:

function boolean hasLoop(Node startNode){
  Node slowNode = Node fastNode1 = Node fastNode2 = startNode;
  while (slowNode && fastNode1 = fastNode2.next() && fastNode2 = fastNode1.next()){
    if (slowNode == fastNode1 || slowNode == fastNode2) return true;
    slowNode = slowNode.next();
  }
  return false;
}
[еще 117] информация о Википедии: находящий цикл алгоритм Floyd .

46
ответ дан Baishampayan Ghose 26 November 2019 в 22:07
поделиться

Абсолютно. Одно решение действительно может пересекать список с обоими указателями, одно перемещение в два раза уровень другого.

Запускаются с 'медленного' и 'быстрого' указателя, указывающего на любое местоположение в списке. Выполните пересекающийся цикл. Если 'быстрый' указатель когда-либо прибывает для совпадения с медленным указателем, у Вас есть круговой связанный список.

int *head = list.GetHead();
if (head != null) {
    int *fastPtr = head;
    int *slowPtr = head;

    bool isCircular = true;

    do 
    {
        if (fastPtr->Next == null || fastPtr->Next->Next == null) //List end found
        {
            isCircular = false;
            break;
        }

        fastPtr = fastPtr->Next->Next;
        slowPtr = slowPtr->Next;
    } while (fastPtr != slowPtr);

    //Do whatever you want with the 'isCircular' flag here
}
9
ответ дан Frederick The Fool 26 November 2019 в 22:07
поделиться

Можно использовать Черепаха и Кролик алгоритм.

Википедия имеет объяснение также, и они называют ее" находящий цикл алгоритм Floyd " или "Черепаха и заяц"

17
ответ дан Nightfirecat 26 November 2019 в 22:07
поделиться

Я попытался решить это сам и нашел другое (менее эффективное, но все же оптимальное) решение.

Идея основана на обращении односвязного списка за линейное время. Это можно сделать, выполнив два перестановки на каждом шаге итерации по списку. Если q - предыдущий элемент (изначально нулевой), а p - текущий, то swap (q, p-> next) swap (p, q) перевернет ссылку и продвинет два указателя одновременно. Перестановки могут быть выполнены с использованием XOR, чтобы предотвратить необходимость использования третьей области памяти.

Если список имеет цикл, то в какой-то момент во время итерации вы попадете на узел, указатель которого уже был изменен. Вы не можете знать, какой это узел, но продолжая итерацию, меняя местами два элемента, вы снова попадаете в начало списка.

Если дважды перевернуть список,

3
ответ дан 26 November 2019 в 22:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: