Вы можете использовать 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 секунды .
Результат:
Я предложил бы использовать 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 .
Абсолютно. Одно решение действительно может пересекать список с обоими указателями, одно перемещение в два раза уровень другого.
Запускаются с 'медленного' и 'быстрого' указателя, указывающего на любое местоположение в списке. Выполните пересекающийся цикл. Если 'быстрый' указатель когда-либо прибывает для совпадения с медленным указателем, у Вас есть круговой связанный список.
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
}
Можно использовать Черепаха и Кролик алгоритм.
Википедия имеет объяснение также, и они называют ее" находящий цикл алгоритм Floyd " или "Черепаха и заяц"
Я попытался решить это сам и нашел другое (менее эффективное, но все же оптимальное) решение.
Идея основана на обращении односвязного списка за линейное время. Это можно сделать, выполнив два перестановки на каждом шаге итерации по списку. Если q - предыдущий элемент (изначально нулевой), а p - текущий, то swap (q, p-> next) swap (p, q) перевернет ссылку и продвинет два указателя одновременно. Перестановки могут быть выполнены с использованием XOR, чтобы предотвратить необходимость использования третьей области памяти.
Если список имеет цикл, то в какой-то момент во время итерации вы попадете на узел, указатель которого уже был изменен. Вы не можете знать, какой это узел, но продолжая итерацию, меняя местами два элемента, вы снова попадаете в начало списка.
Если дважды перевернуть список,