Merge remote-tracking branch 'origin/app' into app
# Conflicts: # pubspec.yaml
This commit is contained in:
199
lib/components/toly_ui/popable/drop_selectable_widget.dart
Normal file
199
lib/components/toly_ui/popable/drop_selectable_widget.dart
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
typedef OnDropSelected = void Function(int index);
|
||||||
|
|
||||||
|
class DropSelectableWidget extends StatefulWidget {
|
||||||
|
final List<String> data;
|
||||||
|
final OnDropSelected? onDropSelected;
|
||||||
|
final Color disableColor;
|
||||||
|
final double iconSize;
|
||||||
|
final double height;
|
||||||
|
final double width;
|
||||||
|
final double fontSize;
|
||||||
|
|
||||||
|
const DropSelectableWidget(
|
||||||
|
{Key? key,
|
||||||
|
this.data = const [],
|
||||||
|
this.onDropSelected,
|
||||||
|
this.disableColor = Colors.black,
|
||||||
|
this.iconSize = 24,
|
||||||
|
this.height = 30,
|
||||||
|
this.width = 200,
|
||||||
|
this.fontSize = 14,
|
||||||
|
})
|
||||||
|
: super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_DropSelectableWidgetState createState() => _DropSelectableWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DropSelectableWidgetState extends State<DropSelectableWidget>
|
||||||
|
with SingleTickerProviderStateMixin {
|
||||||
|
late FocusNode _node;
|
||||||
|
bool _focused = false;
|
||||||
|
late FocusAttachment _nodeAttachment;
|
||||||
|
OverlayEntry? _overlayEntry;
|
||||||
|
late AnimationController _ctrl;
|
||||||
|
late Animation<double> animation;
|
||||||
|
final LayerLink layerLink = LayerLink();
|
||||||
|
|
||||||
|
int _selectedIndex = 0;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
_ctrl = AnimationController(
|
||||||
|
vsync: this,
|
||||||
|
duration: const Duration(milliseconds: 200),
|
||||||
|
);
|
||||||
|
|
||||||
|
animation = Tween<double>(begin: 0, end: pi).animate(_ctrl);
|
||||||
|
_node = FocusNode()
|
||||||
|
..addListener(() {
|
||||||
|
if (_node.hasFocus != _focused) {
|
||||||
|
if (!_focused) {
|
||||||
|
_ctrl.forward();
|
||||||
|
_showOverlay();
|
||||||
|
} else {
|
||||||
|
_hideOverlay();
|
||||||
|
_ctrl.reverse();
|
||||||
|
}
|
||||||
|
setState(() {
|
||||||
|
_focused = _node.hasFocus;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_nodeAttachment = _node.attach(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_node.dispose();
|
||||||
|
_ctrl.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
_nodeAttachment.reparent();
|
||||||
|
return GestureDetector(
|
||||||
|
behavior: HitTestBehavior.opaque,
|
||||||
|
onTap: () {
|
||||||
|
if (_focused) {
|
||||||
|
_node.unfocus();
|
||||||
|
} else {
|
||||||
|
_node.requestFocus();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: CompositedTransformTarget(
|
||||||
|
link: layerLink,
|
||||||
|
child: buildTarget(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _showOverlay() {
|
||||||
|
_overlayEntry = _createOverlayEntry();
|
||||||
|
Overlay.of(context)?.insert(_overlayEntry!);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _hideOverlay() {
|
||||||
|
_overlayEntry?.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildTarget() {
|
||||||
|
return Container(
|
||||||
|
width: widget.width,
|
||||||
|
height: widget.height,
|
||||||
|
padding: const EdgeInsets.only(left: 10, right: 10),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
border: Border.all(
|
||||||
|
width: _focused ?1:1/View.of(context).devicePixelRatio,
|
||||||
|
color: _focused ? Colors.blue : widget.disableColor,
|
||||||
|
)),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
widget.data.isNotEmpty ? widget.data[_selectedIndex] : "暂无数据",style: TextStyle(
|
||||||
|
height: 1,
|
||||||
|
fontSize: widget.fontSize
|
||||||
|
),),
|
||||||
|
AnimatedBuilder(
|
||||||
|
animation: animation,
|
||||||
|
builder: (_, child) => Transform.rotate(
|
||||||
|
angle: animation.value,
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
child: Icon(
|
||||||
|
Icons.keyboard_arrow_down,
|
||||||
|
size: widget.iconSize,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
OverlayEntry _createOverlayEntry() => OverlayEntry(
|
||||||
|
builder: (BuildContext context) => UnconstrainedBox(
|
||||||
|
child: CompositedTransformFollower(
|
||||||
|
link: layerLink,
|
||||||
|
targetAnchor: Alignment.bottomCenter,
|
||||||
|
followerAnchor: Alignment.topCenter,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 4.0),
|
||||||
|
child: Material(
|
||||||
|
shape: const RoundedRectangleBorder(
|
||||||
|
side: BorderSide.none,
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(5))),
|
||||||
|
elevation: 1,
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(5),
|
||||||
|
child: Container(
|
||||||
|
height: 200,
|
||||||
|
// alignment: Alignment.center,
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
color: Color(0xffDAE3FF),
|
||||||
|
),
|
||||||
|
// padding: const EdgeInsets.only(top: 5),
|
||||||
|
width: widget.width,
|
||||||
|
child: CupertinoScrollbar(
|
||||||
|
child: ListView.builder(
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
// shrinkWrap: true,
|
||||||
|
itemCount: widget.data.length,
|
||||||
|
itemBuilder: _buildItem),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildItem(BuildContext context, int index) {
|
||||||
|
return Material(
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () {
|
||||||
|
if (_selectedIndex != index) widget.onDropSelected?.call(index);
|
||||||
|
_selectedIndex = index;
|
||||||
|
_overlayEntry?.markNeedsBuild();
|
||||||
|
_node.unfocus();
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
color: index == _selectedIndex
|
||||||
|
? Colors.blue.withOpacity(0.2)
|
||||||
|
: Colors.transparent,
|
||||||
|
child: Text(widget.data[index],style: TextStyle(fontSize: widget.fontSize),)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
|
|
||||||
export 'navigation/menu_meta.dart';
|
export 'navigation/menu_meta.dart';
|
||||||
export 'navigation/toly_breadcrumb.dart';
|
export 'navigation/toly_breadcrumb.dart';
|
||||||
export 'navigation/toly_navigation_rail.dart';
|
export 'navigation/toly_navigation_rail.dart';
|
||||||
|
export 'popable/drop_selectable_widget.dart';
|
||||||
@@ -328,7 +328,6 @@ class _SortPageState extends State<SortPage> {
|
|||||||
// 从最后一个非叶子节点开始,构建最大堆
|
// 从最后一个非叶子节点开始,构建最大堆
|
||||||
for (int i = numbers.length ~/ 2; i >= 0; i--) {
|
for (int i = numbers.length ~/ 2; i >= 0; i--) {
|
||||||
await heapify(numbers, numbers.length, i);
|
await heapify(numbers, numbers.length, i);
|
||||||
streamController.add(numbers);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 依次取出最大堆的根节点(最大值),并进行堆化
|
// 依次取出最大堆的根节点(最大值),并进行堆化
|
||||||
@@ -361,6 +360,7 @@ class _SortPageState extends State<SortPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await Future.delayed(getDuration()); // 延迟操作,用于可视化排序过程
|
await Future.delayed(getDuration()); // 延迟操作,用于可视化排序过程
|
||||||
|
streamController.add(numbers);
|
||||||
}
|
}
|
||||||
|
|
||||||
///插入排序
|
///插入排序
|
||||||
@@ -448,7 +448,7 @@ class _SortPageState extends State<SortPage> {
|
|||||||
///快速排序
|
///快速排序
|
||||||
quickSort(int leftIndex, int rightIndex) async {
|
quickSort(int leftIndex, int rightIndex) async {
|
||||||
// 定义一个名为 _partition 的异步函数,用于划分数组,并返回划分后的基准元素的索引位置
|
// 定义一个名为 _partition 的异步函数,用于划分数组,并返回划分后的基准元素的索引位置
|
||||||
Future<int> _partition(int left, int right) async {
|
Future<int> _partition(int left, int right) async{
|
||||||
// 选择中间位置的元素作为基准元素
|
// 选择中间位置的元素作为基准元素
|
||||||
int p = (left + (right - left) / 2).toInt();
|
int p = (left + (right - left) / 2).toInt();
|
||||||
|
|
||||||
|
|||||||
@@ -7,14 +7,16 @@ import '../../../pages/color/color_detail_page.dart';
|
|||||||
import '../../../pages/color/color_page.dart';
|
import '../../../pages/color/color_page.dart';
|
||||||
import '../../../pages/empty/empty_page.dart';
|
import '../../../pages/empty/empty_page.dart';
|
||||||
import '../../../pages/settings/settings_page.dart';
|
import '../../../pages/settings/settings_page.dart';
|
||||||
|
import '../../../pages/user/user_page.dart';
|
||||||
import '../../../pages/counter/counter_page.dart';
|
import '../../../pages/counter/counter_page.dart';
|
||||||
import '../../../pages/sort/sort_page.dart';
|
import '../../../pages/sort/views/sort_page.dart';
|
||||||
import '../transition/fade_transition_page.dart';
|
import '../transition/fade_transition_page.dart';
|
||||||
import '../../../pages/color/color_add_page.dart';
|
import '../../../pages/color/color_add_page.dart';
|
||||||
|
|
||||||
const List<String> kDestinationsPaths = [
|
const List<String> kDestinationsPaths = [
|
||||||
'/color',
|
'/color',
|
||||||
'/counter',
|
'/counter',
|
||||||
|
'/sort',
|
||||||
'/user',
|
'/user',
|
||||||
'/settings',
|
'/settings',
|
||||||
];
|
];
|
||||||
@@ -29,8 +31,9 @@ class AppRouterDelegate extends RouterDelegate<Object> with ChangeNotifier {
|
|||||||
int? get activeIndex {
|
int? get activeIndex {
|
||||||
if(path.startsWith('/color')) return 0;
|
if(path.startsWith('/color')) return 0;
|
||||||
if(path.startsWith('/counter')) return 1;
|
if(path.startsWith('/counter')) return 1;
|
||||||
if(path.startsWith('/user')) return 2;
|
if(path.startsWith('/sort')) return 2;
|
||||||
if(path.startsWith('/settings')) return 3;
|
if(path.startsWith('/user')) return 3;
|
||||||
|
if(path.startsWith('/settings')) return 4;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,9 +98,12 @@ class AppRouterDelegate extends RouterDelegate<Object> with ChangeNotifier {
|
|||||||
child = const CounterPage();
|
child = const CounterPage();
|
||||||
}
|
}
|
||||||
if (path == kDestinationsPaths[2]) {
|
if (path == kDestinationsPaths[2]) {
|
||||||
child = const SortPage();
|
child = SortPage();
|
||||||
}
|
}
|
||||||
if (path == kDestinationsPaths[3]) {
|
if (path == kDestinationsPaths[3]) {
|
||||||
|
child = const UserPage();
|
||||||
|
}
|
||||||
|
if (path == kDestinationsPaths[4]) {
|
||||||
child = const SettingPage();
|
child = const SettingPage();
|
||||||
}
|
}
|
||||||
return [
|
return [
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import '../../../pages/sort/sort_setting.dart';
|
||||||
import '../router/app_router_delegate.dart';
|
import '../router/app_router_delegate.dart';
|
||||||
import 'app_navigation_rail.dart';
|
import 'app_navigation_rail.dart';
|
||||||
import 'app_top_bar.dart';
|
import 'app_top_bar.dart';
|
||||||
@@ -10,6 +11,9 @@ class AppNavigation extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
double px1 = 1/View.of(context).devicePixelRatio;
|
double px1 = 1/View.of(context).devicePixelRatio;
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
endDrawer: Drawer(
|
||||||
|
child: SortSettings(),
|
||||||
|
),
|
||||||
body: Row(
|
body: Row(
|
||||||
children: [
|
children: [
|
||||||
const AppNavigationRail(),
|
const AppNavigationRail(),
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ class _AppNavigationRailState extends State<AppNavigationRail> {
|
|||||||
final List<MenuMeta> deskNavBarMenus = const [
|
final List<MenuMeta> deskNavBarMenus = const [
|
||||||
MenuMeta(label: '颜色板', icon: Icons.color_lens_outlined),
|
MenuMeta(label: '颜色板', icon: Icons.color_lens_outlined),
|
||||||
MenuMeta(label: '计数器', icon: Icons.add_chart),
|
MenuMeta(label: '计数器', icon: Icons.add_chart),
|
||||||
|
MenuMeta(label: '排序', icon: Icons.sort),
|
||||||
MenuMeta(label: '我的', icon: Icons.person),
|
MenuMeta(label: '我的', icon: Icons.person),
|
||||||
MenuMeta(label: '设置', icon: Icons.settings),
|
MenuMeta(label: '设置', icon: Icons.settings),
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:iroute/components/toly_ui/button/hover_icon_button.dart';
|
import 'package:iroute/components/toly_ui/button/hover_icon_button.dart';
|
||||||
|
import 'package:iroute/components/toly_ui/popable/drop_selectable_widget.dart';
|
||||||
|
import '../../../pages/sort/functions.dart';
|
||||||
|
import '../../../pages/sort/views/sort_bar.dart';
|
||||||
|
import '../../../pages/sort/views/sort_button.dart';
|
||||||
import '../router/app_router_delegate.dart';
|
import '../router/app_router_delegate.dart';
|
||||||
|
|
||||||
class AppRouterEditor extends StatefulWidget {
|
class AppRouterEditor extends StatefulWidget {
|
||||||
@@ -25,6 +29,9 @@ class _AppRouterEditorState extends State<AppRouterEditor> {
|
|||||||
|
|
||||||
void _onRouteChange() {
|
void _onRouteChange() {
|
||||||
_controller.text=router.path;
|
_controller.text=router.path;
|
||||||
|
setState(() {
|
||||||
|
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -36,29 +43,37 @@ class _AppRouterEditorState extends State<AppRouterEditor> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Stack(
|
print(router.path);
|
||||||
alignment: Alignment.centerRight,
|
if(router.path=='/sort'){
|
||||||
children: [
|
return SortBar();
|
||||||
SizedBox(
|
}
|
||||||
child: CupertinoTextField(
|
|
||||||
controller: _controller,
|
return SizedBox(
|
||||||
style: TextStyle(fontSize: 14),
|
width: 250,
|
||||||
padding: EdgeInsets.only(left:12,top: 6,bottom: 6,right: 32),
|
child: Stack(
|
||||||
placeholder: '输入路由地址导航',
|
alignment: Alignment.centerRight,
|
||||||
onSubmitted: widget.onSubmit,
|
children: [
|
||||||
decoration: BoxDecoration(color: Color(0xffF1F2F3),borderRadius: BorderRadius.circular(6)),
|
SizedBox(
|
||||||
|
child: CupertinoTextField(
|
||||||
|
controller: _controller,
|
||||||
|
style: TextStyle(fontSize: 14),
|
||||||
|
padding: EdgeInsets.only(left:12,top: 6,bottom: 6,right: 32),
|
||||||
|
placeholder: '输入路由地址导航',
|
||||||
|
onSubmitted: widget.onSubmit,
|
||||||
|
decoration: BoxDecoration(color: Color(0xffF1F2F3),borderRadius: BorderRadius.circular(6)),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
Padding(
|
||||||
Padding(
|
padding: const EdgeInsets.only(right: 8.0),
|
||||||
padding: const EdgeInsets.only(right: 8.0),
|
child: HoverIconButton(
|
||||||
child: HoverIconButton(
|
icon: Icons.directions_outlined,
|
||||||
icon: Icons.directions_outlined,
|
defaultColor: Color(0xff68696B),
|
||||||
defaultColor: Color(0xff68696B),
|
onPressed:()=>widget.onSubmit?.call(_controller.text),
|
||||||
onPressed:()=>widget.onSubmit?.call(_controller.text),
|
size: 20
|
||||||
size: 20
|
),
|
||||||
),
|
)
|
||||||
)
|
],
|
||||||
],
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:iroute/components/components.dart';
|
import 'package:iroute/components/components.dart';
|
||||||
|
import '../../../pages/sort/functions.dart';
|
||||||
import '../router/app_router_delegate.dart';
|
import '../router/app_router_delegate.dart';
|
||||||
import 'app_router_editor.dart';
|
import 'app_router_editor.dart';
|
||||||
|
|
||||||
@@ -20,7 +21,7 @@ class AppTopBar extends StatelessWidget {
|
|||||||
child: Row(children: [
|
child: Row(children: [
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 250,
|
// width: 200,
|
||||||
child: AppRouterEditor(
|
child: AppRouterEditor(
|
||||||
onSubmit: (path) => router.path = path,
|
onSubmit: (path) => router.path = path,
|
||||||
)),
|
)),
|
||||||
@@ -52,6 +53,7 @@ Map<String, String> kRouteLabelMap = {
|
|||||||
'/color/detail': '颜色详情',
|
'/color/detail': '颜色详情',
|
||||||
'/counter': '计数器',
|
'/counter': '计数器',
|
||||||
'/user': '我的',
|
'/user': '我的',
|
||||||
|
'/sort': '可视化排序',
|
||||||
'/settings': '系统设置',
|
'/settings': '系统设置',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import '../pages/sort/provider/state.dart';
|
||||||
import 'navigation/router/app_router_delegate.dart';
|
import 'navigation/router/app_router_delegate.dart';
|
||||||
import 'navigation/views/app_navigation.dart';
|
import 'navigation/views/app_navigation.dart';
|
||||||
import 'navigation/views/app_navigation_rail.dart';
|
import 'navigation/views/app_navigation_rail.dart';
|
||||||
@@ -8,20 +9,23 @@ class UnitApp extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
return SortStateScope(
|
||||||
theme: ThemeData(
|
notifier: SortState(),
|
||||||
fontFamily: "宋体",
|
child: MaterialApp(
|
||||||
scaffoldBackgroundColor: Colors.white,
|
theme: ThemeData(
|
||||||
appBarTheme: const AppBarTheme(
|
fontFamily: "宋体",
|
||||||
elevation: 0,
|
scaffoldBackgroundColor: Colors.white,
|
||||||
iconTheme: IconThemeData(color: Colors.black),
|
appBarTheme: const AppBarTheme(
|
||||||
titleTextStyle: TextStyle(
|
elevation: 0,
|
||||||
color: Colors.black,
|
iconTheme: IconThemeData(color: Colors.black),
|
||||||
fontSize: 18,
|
titleTextStyle: TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
color: Colors.black,
|
||||||
))),
|
fontSize: 18,
|
||||||
debugShowCheckedModeBanner: false,
|
fontWeight: FontWeight.bold,
|
||||||
home: AppNavigation()
|
))),
|
||||||
|
debugShowCheckedModeBanner: false,
|
||||||
|
home: AppNavigation()
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
46
lib/v5/pages/sort/functions.dart
Normal file
46
lib/v5/pages/sort/functions.dart
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import 'functions/bubble.dart';
|
||||||
|
import 'functions/cocktail.dart';
|
||||||
|
import 'functions/comb.dart';
|
||||||
|
import 'functions/cycle.dart';
|
||||||
|
import 'functions/gnome.dart';
|
||||||
|
import 'functions/heap.dart';
|
||||||
|
import 'functions/insertion.dart';
|
||||||
|
import 'functions/merage.dart';
|
||||||
|
import 'functions/pigeonHole.dart';
|
||||||
|
import 'functions/quick.dart';
|
||||||
|
import 'functions/selection.dart';
|
||||||
|
import 'functions/shell.dart';
|
||||||
|
|
||||||
|
typedef SortFunction = Future<void> Function(List<int> src, SortCallback callback);
|
||||||
|
typedef SortCallback = Future<void> Function(List<int> dist);
|
||||||
|
|
||||||
|
Map<String, SortFunction> sortFunctionMap = {
|
||||||
|
'insertion': insertionSort,
|
||||||
|
'bubble': bubbleSort,
|
||||||
|
'cocktail': cocktailSort,
|
||||||
|
'comb': combSort,
|
||||||
|
'pigeonHole': pigeonHoleSort,
|
||||||
|
'shell': shellSort,
|
||||||
|
'selection': selectionSort,
|
||||||
|
'gnome': gnomeSort,
|
||||||
|
'cycle': cycleSort,
|
||||||
|
'heap': heapSort,
|
||||||
|
'quick': quickSort,
|
||||||
|
'mergeSort': mergeSort,
|
||||||
|
};
|
||||||
|
|
||||||
|
Map<String, String> sortNameMap = {
|
||||||
|
'insertion': '插入排序',
|
||||||
|
'bubble': '冒泡排序',
|
||||||
|
'cocktail': '鸡尾酒排序(双向冒泡排序)',
|
||||||
|
'comb': '梳排序',
|
||||||
|
'pigeonHole': '鸽巢排序',
|
||||||
|
'shell': '希尔排序',
|
||||||
|
'selection': '选择排序',
|
||||||
|
'gnome': '侏儒排序',
|
||||||
|
'cycle': '循环排序',
|
||||||
|
'heap': '堆排序',
|
||||||
|
'quick': '快速排序',
|
||||||
|
'mergeSort': '归并排序',
|
||||||
|
};
|
||||||
|
|
||||||
19
lib/v5/pages/sort/functions/bubble.dart
Normal file
19
lib/v5/pages/sort/functions/bubble.dart
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import '../functions.dart';
|
||||||
|
|
||||||
|
///冒泡排序
|
||||||
|
Future<void> bubbleSort(List<int> src, SortCallback callback ) async{
|
||||||
|
//控制需要进行排序的次数。每一轮循环都会确定一个数字的最终位置。
|
||||||
|
for (int i = 0; i < src.length; ++i) {
|
||||||
|
//遍历当前未排序的元素,通过相邻的元素比较并交换位置来完成排序。
|
||||||
|
for (int j = 0; j < src.length - i - 1; ++j) {
|
||||||
|
//如果 _numbers[j] 大于 _numbers[j + 1],则交换它们的位置,确保较大的元素移到右边。
|
||||||
|
if (src[j] > src[j + 1]) {
|
||||||
|
int temp = src[j];
|
||||||
|
src[j] = src[j + 1];
|
||||||
|
src[j + 1] = temp;
|
||||||
|
}
|
||||||
|
//实现一个延迟,以便在ui上展示排序的动画效果
|
||||||
|
await callback(src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
52
lib/v5/pages/sort/functions/cocktail.dart
Normal file
52
lib/v5/pages/sort/functions/cocktail.dart
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import '../functions.dart';
|
||||||
|
|
||||||
|
///鸡尾酒排序(双向冒泡排序)
|
||||||
|
Future<void> cocktailSort(List<int> src, SortCallback callback ) async {
|
||||||
|
bool swapped = true; // 表示是否进行了交换
|
||||||
|
int start = 0; // 当前未排序部分的起始位置
|
||||||
|
int end = src.length; // 当前未排序部分的结束位置
|
||||||
|
|
||||||
|
// 开始排序循环,只有当没有进行交换时才会退出循环
|
||||||
|
while (swapped == true) {
|
||||||
|
swapped = false;
|
||||||
|
|
||||||
|
// 从左往右遍历需要排序的部分
|
||||||
|
for (int i = start; i < end - 1; ++i) {
|
||||||
|
// 对每两个相邻元素进行比较
|
||||||
|
if (src[i] > src[i + 1]) {
|
||||||
|
// 如果前面的元素大于后面的元素,则交换它们的位置
|
||||||
|
int temp = src[i];
|
||||||
|
src[i] = src[i + 1];
|
||||||
|
src[i + 1] = temp;
|
||||||
|
swapped = true; // 进行了交换
|
||||||
|
}
|
||||||
|
|
||||||
|
// 实现动画效果,延迟一段时间后更新数组状态
|
||||||
|
await callback(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没有进行交换,则说明已经排好序,退出循环
|
||||||
|
if (swapped == false) break;
|
||||||
|
// 重设为false,准备进行下一轮排序
|
||||||
|
swapped = false;
|
||||||
|
// 将end设置为上一轮排序的最后一个元素的位置
|
||||||
|
end = end - 1;
|
||||||
|
|
||||||
|
// 从右往左遍历需要排序的部分
|
||||||
|
for (int i = end - 1; i >= start; i--) {
|
||||||
|
// 对每两个相邻元素进行比较
|
||||||
|
if (src[i] > src[i + 1]) {
|
||||||
|
// 如果前面的元素大于后面的元素,则交换它们的位置
|
||||||
|
int temp = src[i];
|
||||||
|
src[i] = src[i + 1];
|
||||||
|
src[i + 1] = temp;
|
||||||
|
swapped = true; // 进行了交换
|
||||||
|
}
|
||||||
|
|
||||||
|
// 实现动画效果,延迟一段时间后更新数组状态
|
||||||
|
await callback(src);
|
||||||
|
}
|
||||||
|
// 将start向右移一位,准备下一轮排序
|
||||||
|
start = start + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
34
lib/v5/pages/sort/functions/comb.dart
Normal file
34
lib/v5/pages/sort/functions/comb.dart
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import '../functions.dart';
|
||||||
|
|
||||||
|
///梳排序(Comb Sort)
|
||||||
|
Future<void> combSort(List<int> src, SortCallback callback) async{
|
||||||
|
int gap = src.length;
|
||||||
|
|
||||||
|
bool swapped = true;
|
||||||
|
|
||||||
|
// 当间隔不为1或存在交换时执行循环
|
||||||
|
while (gap != 1 || swapped == true) {
|
||||||
|
// 通过缩小间隔来逐步将元素归位
|
||||||
|
gap = getNextGap(gap);
|
||||||
|
swapped = false;
|
||||||
|
for (int i = 0; i < src.length - gap; i++) {
|
||||||
|
// 如果当前元素大于间隔位置上的元素,则交换它们的位置
|
||||||
|
if (src[i] > src[i + gap]) {
|
||||||
|
int temp = src[i];
|
||||||
|
src[i] = src[i + gap];
|
||||||
|
src[i + gap] = temp;
|
||||||
|
swapped = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 实现一个延迟,以便在 UI 上展示排序的动画效果。
|
||||||
|
await callback(src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int getNextGap(int gap) {
|
||||||
|
// 根据当前间隔值计算下一个间隔值
|
||||||
|
gap = (gap * 10) ~/ 13;
|
||||||
|
if (gap < 1) return 1;
|
||||||
|
return gap;
|
||||||
|
}
|
||||||
54
lib/v5/pages/sort/functions/cycle.dart
Normal file
54
lib/v5/pages/sort/functions/cycle.dart
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import '../functions.dart';
|
||||||
|
|
||||||
|
///循环排序
|
||||||
|
Future<void> cycleSort(List<int> src, SortCallback callback) async {
|
||||||
|
int writes = 0;
|
||||||
|
for (int cycleStart = 0; cycleStart <= src.length - 2; cycleStart++) {
|
||||||
|
int item = src[cycleStart];
|
||||||
|
int pos = cycleStart;
|
||||||
|
|
||||||
|
// 在未排序部分中寻找比当前元素小的元素个数
|
||||||
|
for (int i = cycleStart + 1; i < src.length; i++) {
|
||||||
|
if (src[i] < item) pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果当前元素已经在正确位置上,则跳过此次迭代
|
||||||
|
if (pos == cycleStart) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将当前元素放置到正确的位置上,并记录写操作次数
|
||||||
|
while (item == src[pos]) {
|
||||||
|
pos += 1;
|
||||||
|
}
|
||||||
|
if (pos != cycleStart) {
|
||||||
|
int temp = item;
|
||||||
|
item = src[pos];
|
||||||
|
src[pos] = temp;
|
||||||
|
writes++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 循环将位于当前位置的元素放置到正确的位置上
|
||||||
|
while (pos != cycleStart) {
|
||||||
|
pos = cycleStart;
|
||||||
|
// 继续在未排序部分中寻找比当前元素小的元素个数
|
||||||
|
for (int i = cycleStart + 1; i < src.length; i++) {
|
||||||
|
if (src[i] < item) pos += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将当前元素放置到正确的位置上,并记录写操作次数
|
||||||
|
while (item == src[pos]) {
|
||||||
|
pos += 1;
|
||||||
|
}
|
||||||
|
if (item != src[pos]) {
|
||||||
|
int temp = item;
|
||||||
|
item = src[pos];
|
||||||
|
src[pos] = temp;
|
||||||
|
writes++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加延迟操作以展示排序过程
|
||||||
|
await callback(src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
22
lib/v5/pages/sort/functions/gnome.dart
Normal file
22
lib/v5/pages/sort/functions/gnome.dart
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import '../functions.dart';
|
||||||
|
|
||||||
|
///地精排序 (侏儒排序)
|
||||||
|
Future<void> gnomeSort(List<int> src, SortCallback callback) async {
|
||||||
|
int index = 0;
|
||||||
|
while (index < src.length) {
|
||||||
|
// 当 index 小于数组长度时执行循环
|
||||||
|
if (index == 0) index++;
|
||||||
|
if (src[index] >= src[index - 1]) {
|
||||||
|
// 如果当前元素大于等于前面的元素,则将 index 加1
|
||||||
|
index++;
|
||||||
|
} else {
|
||||||
|
// 否则,交换这两个元素,并将 index 减1(使得元素可以沉到正确位置)
|
||||||
|
int temp = src[index];
|
||||||
|
src[index] = src[index - 1];
|
||||||
|
src[index - 1] = temp;
|
||||||
|
index--;
|
||||||
|
}
|
||||||
|
await callback(src);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
38
lib/v5/pages/sort/functions/heap.dart
Normal file
38
lib/v5/pages/sort/functions/heap.dart
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import '../functions.dart';
|
||||||
|
|
||||||
|
///堆排序
|
||||||
|
Future<void> heapSort(List<int> src, SortCallback callback) async {
|
||||||
|
// 从最后一个非叶子节点开始,构建最大堆
|
||||||
|
for (int i = src.length ~/ 2; i >= 0; i--) {
|
||||||
|
await heapify(src,callback, src.length, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 依次取出最大堆的根节点(最大值),并进行堆化
|
||||||
|
for (int i = src.length - 1; i >= 0; i--) {
|
||||||
|
int temp = src[0];
|
||||||
|
src[0] = src[i];
|
||||||
|
src[i] = temp;
|
||||||
|
await heapify(src, callback,i, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> heapify(List<int> src, SortCallback callback, int n, int i) async{
|
||||||
|
int largest = i;
|
||||||
|
int l = 2 * i + 1; // 左子节点索引
|
||||||
|
int r = 2 * i + 2; // 右子节点索引
|
||||||
|
|
||||||
|
// 如果左子节点存在并且大于父节点,则更新最大值索引
|
||||||
|
if (l < n && src[l] > src[largest]) largest = l;
|
||||||
|
|
||||||
|
// 如果右子节点存在并且大于父节点或左子节点,则更新最大值索引
|
||||||
|
if (r < n && src[r] > src[largest]) largest = r;
|
||||||
|
|
||||||
|
// 如果最大值索引不等于当前节点索引,则交换节点值,并递归进行堆化
|
||||||
|
if (largest != i) {
|
||||||
|
int temp = src[i];
|
||||||
|
src[i] = src[largest];
|
||||||
|
src[largest] = temp;
|
||||||
|
heapify(src,callback, n, largest);
|
||||||
|
}
|
||||||
|
await callback(src);
|
||||||
|
}
|
||||||
19
lib/v5/pages/sort/functions/insertion.dart
Normal file
19
lib/v5/pages/sort/functions/insertion.dart
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import '../functions.dart';
|
||||||
|
|
||||||
|
///插入排序
|
||||||
|
Future<void> insertionSort(List<int> src, SortCallback callback) async {
|
||||||
|
for (int i = 1; i < src.length; i++) {
|
||||||
|
int temp = src[i]; // 将当前元素存储到临时变量 temp 中
|
||||||
|
int j = i - 1; // j 表示已排序部分的最后一个元素的索引
|
||||||
|
|
||||||
|
// 在已排序部分从后往前查找,找到合适位置插入当前元素
|
||||||
|
while (j >= 0 && temp < src[j]) {
|
||||||
|
src[j + 1] = src[j]; // 当前元素比已排序部分的元素小,将元素后移一位
|
||||||
|
--j; // 向前遍历
|
||||||
|
// 更新排序结果回调
|
||||||
|
await callback(src);
|
||||||
|
}
|
||||||
|
src[j + 1] = temp; // 插入当前元素到已排序部分的正确位置
|
||||||
|
await callback(src);
|
||||||
|
}
|
||||||
|
}
|
||||||
79
lib/v5/pages/sort/functions/merage.dart
Normal file
79
lib/v5/pages/sort/functions/merage.dart
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
import '../functions.dart';
|
||||||
|
|
||||||
|
//快速排序
|
||||||
|
Future<void> mergeSort(List<int> src, SortCallback callback) async {
|
||||||
|
await _mergeSort(src,callback,0,src.length-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
///归并排序
|
||||||
|
Future<void> _mergeSort(List<int> src, SortCallback callback,int leftIndex, int rightIndex) async {
|
||||||
|
// 定义一个名为 merge 的异步函数,用于合并两个有序子数组
|
||||||
|
Future<void> merge(int leftIndex, int middleIndex, int rightIndex) async {
|
||||||
|
// 计算左侧子数组和右侧子数组的大小
|
||||||
|
int leftSize = middleIndex - leftIndex + 1;
|
||||||
|
int rightSize = rightIndex - middleIndex;
|
||||||
|
|
||||||
|
// 创建左侧子数组和右侧子数组
|
||||||
|
List leftList = List.generate(leftSize, (index) => 0);
|
||||||
|
List rightList = List.generate(rightSize, (index) => 0);
|
||||||
|
|
||||||
|
// 将原始数组中的元素分别复制到左侧子数组和右侧子数组中
|
||||||
|
for (int i = 0; i < leftSize; i++) {
|
||||||
|
leftList[i] = src[leftIndex + i];
|
||||||
|
}
|
||||||
|
for (int j = 0; j < rightSize; j++) {
|
||||||
|
rightList[j] = src[middleIndex + j + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化游标和索引
|
||||||
|
int i = 0, j = 0;
|
||||||
|
int k = leftIndex;
|
||||||
|
|
||||||
|
// 比较左侧子数组和右侧子数组的元素,并按顺序将较小的元素放入原始数组中
|
||||||
|
while (i < leftSize && j < rightSize) {
|
||||||
|
if (leftList[i] <= rightList[j]) {
|
||||||
|
src[k] = leftList[i];
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
src[k] = rightList[j];
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
|
||||||
|
await callback(src);
|
||||||
|
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将左侧子数组或右侧子数组中剩余的元素放入原始数组中
|
||||||
|
while (i < leftSize) {
|
||||||
|
src[k] = leftList[i];
|
||||||
|
i++;
|
||||||
|
k++;
|
||||||
|
|
||||||
|
await callback(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (j < rightSize) {
|
||||||
|
src[k] = rightList[j];
|
||||||
|
j++;
|
||||||
|
k++;
|
||||||
|
|
||||||
|
await callback(src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果左索引小于右索引,则递归地对数组进行归并排序
|
||||||
|
if (leftIndex < rightIndex) {
|
||||||
|
// 计算中间索引位置
|
||||||
|
int middleIndex = (rightIndex + leftIndex) ~/ 2;
|
||||||
|
|
||||||
|
// 分别对左侧子数组和右侧子数组进行归并排序
|
||||||
|
await _mergeSort(src,callback,leftIndex, middleIndex);
|
||||||
|
await _mergeSort(src,callback,middleIndex + 1, rightIndex);
|
||||||
|
|
||||||
|
await callback(src);
|
||||||
|
|
||||||
|
// 合并两个有序子数组
|
||||||
|
await merge(leftIndex, middleIndex, rightIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
37
lib/v5/pages/sort/functions/oddEven.dart
Normal file
37
lib/v5/pages/sort/functions/oddEven.dart
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import '../functions.dart';
|
||||||
|
|
||||||
|
///奇偶排序(Odd-Even Sort)
|
||||||
|
Future<void> oddEvenSort(List<int> src, SortCallback callback) async {
|
||||||
|
bool isSorted = false;
|
||||||
|
|
||||||
|
while (!isSorted) {
|
||||||
|
// 当 isSorted 为 false 时执行循环
|
||||||
|
isSorted = true; // 先假设数组已经排好序
|
||||||
|
|
||||||
|
for (int i = 1; i <= src.length - 2; i = i + 2) {
|
||||||
|
// 对奇数索引位置进行比较
|
||||||
|
if (src[i] > src[i + 1]) {
|
||||||
|
// 如果当前元素大于后面的元素,则交换它们的值
|
||||||
|
int temp = src[i];
|
||||||
|
src[i] = src[i + 1];
|
||||||
|
src[i + 1] = temp;
|
||||||
|
isSorted = false; // 若发生了交换,则说明数组仍未完全排序,将 isSorted 设为 false
|
||||||
|
await callback(src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i <= src.length - 2; i = i + 2) {
|
||||||
|
// 对偶数索引位置进行比较
|
||||||
|
if (src[i] > src[i + 1]) {
|
||||||
|
// 如果当前元素大于后面的元素,则交换它们的值
|
||||||
|
int temp = src[i];
|
||||||
|
src[i] = src[i + 1];
|
||||||
|
src[i + 1] = temp;
|
||||||
|
isSorted = false;
|
||||||
|
await callback(src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
33
lib/v5/pages/sort/functions/pigeonHole.dart
Normal file
33
lib/v5/pages/sort/functions/pigeonHole.dart
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import '../functions.dart';
|
||||||
|
|
||||||
|
///鸽巢排序
|
||||||
|
Future<void> pigeonHoleSort(List<int> src, SortCallback callback ) async{
|
||||||
|
int min = src[0];
|
||||||
|
int max = src[0];
|
||||||
|
int range, i, j, index;
|
||||||
|
|
||||||
|
// 找到数组中的最大值和最小值
|
||||||
|
for (int a = 0; a < src.length; a++) {
|
||||||
|
if (src[a] > max) max = src[a];
|
||||||
|
if (src[a] < min) min = src[a];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算鸽巢的个数
|
||||||
|
range = max - min + 1;
|
||||||
|
List<int> p = List.generate(range, (i) => 0);
|
||||||
|
|
||||||
|
// 将数字分配到各个鸽巢中
|
||||||
|
for (i = 0; i < src.length; i++) {
|
||||||
|
p[src[i] - min]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
index = 0;
|
||||||
|
|
||||||
|
// 将鸽巢中的数字取出,重新放回到数组中
|
||||||
|
for (j = 0; j < range; j++) {
|
||||||
|
while (p[j]-- > 0) {
|
||||||
|
src[index++] = j + min;
|
||||||
|
await callback(src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
65
lib/v5/pages/sort/functions/quick.dart
Normal file
65
lib/v5/pages/sort/functions/quick.dart
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import '../functions.dart';
|
||||||
|
|
||||||
|
//快速排序
|
||||||
|
Future<void> quickSort(List<int> src, SortCallback callback) async {
|
||||||
|
await _quickSort(src,callback,0,src.length-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
///快速排序
|
||||||
|
Future<void> _quickSort(List<int> src, SortCallback callback,int leftIndex,int rightIndex) async {
|
||||||
|
// 定义一个名为 _partition 的异步函数,用于划分数组,并返回划分后的基准元素的索引位置
|
||||||
|
Future<int> _partition(int left, int right) async {
|
||||||
|
// 选择中间位置的元素作为基准元素
|
||||||
|
int p = (left + (right - left) / 2).toInt();
|
||||||
|
|
||||||
|
// 交换基准元素和最右边的元素
|
||||||
|
var temp = src[p];
|
||||||
|
src[p] = src[right];
|
||||||
|
src[right] = temp;
|
||||||
|
await callback(src);
|
||||||
|
|
||||||
|
// 初始化游标 cursor
|
||||||
|
int cursor = left;
|
||||||
|
|
||||||
|
// 遍历数组并根据基准元素将元素交换到左侧或右侧
|
||||||
|
for (int i = left; i < right; i++) {
|
||||||
|
if (cf(src[i], src[right]) <= 0) {
|
||||||
|
// 如果当前元素小于等于基准元素,则交换它和游标位置的元素
|
||||||
|
var temp = src[i];
|
||||||
|
src[i] = src[cursor];
|
||||||
|
src[cursor] = temp;
|
||||||
|
cursor++;
|
||||||
|
await callback(src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将基准元素放置在游标位置
|
||||||
|
temp = src[right];
|
||||||
|
src[right] = src[cursor];
|
||||||
|
src[cursor] = temp;
|
||||||
|
|
||||||
|
await callback(src);
|
||||||
|
|
||||||
|
return cursor; // 返回基准元素的索引位置
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果左索引小于右索引,则递归地对数组进行快速排序
|
||||||
|
if (leftIndex < rightIndex) {
|
||||||
|
int p = await _partition(leftIndex, rightIndex);
|
||||||
|
|
||||||
|
await _quickSort(src,callback,leftIndex, p - 1); // 对基准元素左侧的子数组进行快速排序
|
||||||
|
|
||||||
|
await _quickSort(src,callback, p + 1, rightIndex); // 对基准元素右侧的子数组进行快速排序
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 比较函数,用于判断两个元素的大小关系
|
||||||
|
cf(int a, int b) {
|
||||||
|
if (a < b) {
|
||||||
|
return -1; // 若 a 小于 b,则返回 -1
|
||||||
|
} else if (a > b) {
|
||||||
|
return 1; // 若 a 大于 b,则返回 1
|
||||||
|
} else {
|
||||||
|
return 0; // 若 a 等于 b,则返回 0
|
||||||
|
}
|
||||||
|
}
|
||||||
18
lib/v5/pages/sort/functions/selection.dart
Normal file
18
lib/v5/pages/sort/functions/selection.dart
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import '../functions.dart';
|
||||||
|
|
||||||
|
///选择排序
|
||||||
|
Future<void> selectionSort(List<int> src, SortCallback callback ) async {
|
||||||
|
for (int i = 0; i < src.length; i++) {
|
||||||
|
for (int j = i + 1; j < src.length; j++) {
|
||||||
|
// 遍历未排序部分,内层循环控制变量 j
|
||||||
|
if (src[i] > src[j]) {
|
||||||
|
// 判断当前元素是否比后续元素小
|
||||||
|
int temp = src[j];
|
||||||
|
// 交换当前元素和后续较小的元素
|
||||||
|
src[j] = src[i];
|
||||||
|
src[i] = temp;
|
||||||
|
}
|
||||||
|
await callback(src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
21
lib/v5/pages/sort/functions/shell.dart
Normal file
21
lib/v5/pages/sort/functions/shell.dart
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import '../functions.dart';
|
||||||
|
|
||||||
|
///希尔排序
|
||||||
|
Future<void> shellSort(List<int> src, SortCallback callback) async{
|
||||||
|
//定义变量 gap 并初始化为数组长度的一半。每次循环完成后将 gap 减半直到等于 0。
|
||||||
|
for (int gap = src.length ~/ 2; gap > 0; gap ~/= 2) {
|
||||||
|
//遍历每个子序列并进行插入排序。初始时从第一个子序列的第二个元素开始,即 i = gap,以 gap 为步长逐个遍历每个子序列。
|
||||||
|
for (int i = gap; i < src.length; i += 1) {
|
||||||
|
//将当前遍历到的元素赋值给它
|
||||||
|
int temp = src[i];
|
||||||
|
//内部使用一个 for 循环来实现插入排序。
|
||||||
|
//循环开始时定义变量 j 并将其初始化为当前遍历到的元素的下标。通过不断比较前后相隔 gap 的元素大小并交换位置,将当前元素插入到正确的位置。
|
||||||
|
int j;
|
||||||
|
for (j = i; j >= gap && src[j - gap] > temp; j -= gap) {
|
||||||
|
src[j] = src[j - gap];
|
||||||
|
}
|
||||||
|
src[j] = temp;
|
||||||
|
await callback(src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
31
lib/v5/pages/sort/provider/sort_config.dart
Normal file
31
lib/v5/pages/sort/provider/sort_config.dart
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class SortConfig {
|
||||||
|
final int count;
|
||||||
|
final int seed;
|
||||||
|
final Duration duration;
|
||||||
|
final String name;
|
||||||
|
|
||||||
|
SortConfig({
|
||||||
|
this.count = 100,
|
||||||
|
this.duration = const Duration(microseconds: 1500),
|
||||||
|
this.seed = -1,
|
||||||
|
this.name = 'insertion',
|
||||||
|
});
|
||||||
|
|
||||||
|
SortConfig copyWith({
|
||||||
|
int? count,
|
||||||
|
int? seed,
|
||||||
|
Duration? duration,
|
||||||
|
String? name,
|
||||||
|
}) =>
|
||||||
|
SortConfig(
|
||||||
|
count:count??this.count,
|
||||||
|
seed:seed??this.seed,
|
||||||
|
duration:duration??this.duration,
|
||||||
|
name:name??this.name,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
78
lib/v5/pages/sort/provider/state.dart
Normal file
78
lib/v5/pages/sort/provider/state.dart
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
|
||||||
|
import '../functions.dart';
|
||||||
|
import 'sort_config.dart';
|
||||||
|
|
||||||
|
enum SortStatus{
|
||||||
|
none, // 未操作
|
||||||
|
sorting, // 排序中
|
||||||
|
sorted, // 排序完成
|
||||||
|
}
|
||||||
|
|
||||||
|
class SortState with ChangeNotifier{
|
||||||
|
|
||||||
|
SortState(){
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
SortStatus status = SortStatus.none;
|
||||||
|
|
||||||
|
List<int> data = [];
|
||||||
|
List<int> stepData = [];
|
||||||
|
|
||||||
|
SortConfig _config = SortConfig();
|
||||||
|
SortConfig get config => _config;
|
||||||
|
Random random = Random();
|
||||||
|
|
||||||
|
set config(SortConfig config){
|
||||||
|
_config = config;
|
||||||
|
reset();
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void reset(){
|
||||||
|
data.clear();
|
||||||
|
status = SortStatus.none;
|
||||||
|
notifyListeners();
|
||||||
|
int count = config.count;
|
||||||
|
if(config.seed!=-1){
|
||||||
|
random = Random(config.seed);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
//随机往数组中填值
|
||||||
|
data.add(random.nextInt(1000));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sort() async{
|
||||||
|
status = SortStatus.sorting;
|
||||||
|
notifyListeners();
|
||||||
|
Stopwatch stopwatch = Stopwatch()..start();
|
||||||
|
SortFunction? sortFunction = sortFunctionMap[config.name];
|
||||||
|
if(sortFunction!=null){
|
||||||
|
await sortFunction(data,(arr) async {
|
||||||
|
await Future.delayed(config.duration);
|
||||||
|
notifyListeners();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
status = SortStatus.sorted;
|
||||||
|
notifyListeners();
|
||||||
|
stopwatch.stop();
|
||||||
|
print("Sorting completed in ${stopwatch.elapsed.inMilliseconds} ms.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Provides the current [SortState] to descendant widgets in the tree.
|
||||||
|
class SortStateScope extends InheritedNotifier<SortState> {
|
||||||
|
const SortStateScope({
|
||||||
|
required super.notifier,
|
||||||
|
required super.child,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
static SortState of(BuildContext context) =>
|
||||||
|
context.dependOnInheritedWidgetOfExactType<SortStateScope>()!.notifier!;
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
109
lib/v5/pages/sort/sort_setting.dart
Normal file
109
lib/v5/pages/sort/sort_setting.dart
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'provider/sort_config.dart';
|
||||||
|
import 'provider/state.dart';
|
||||||
|
|
||||||
|
class SortSettings extends StatefulWidget {
|
||||||
|
|
||||||
|
const SortSettings({super.key,});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<SortSettings> createState() => _SortSettingsState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SortSettingsState extends State<SortSettings> {
|
||||||
|
late TextEditingController _count =
|
||||||
|
TextEditingController();
|
||||||
|
late TextEditingController _duration = TextEditingController();
|
||||||
|
late TextEditingController _seed =
|
||||||
|
TextEditingController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didChangeDependencies() {
|
||||||
|
print('========_SortSettingsState#didChangeDependencies=============');
|
||||||
|
super.didChangeDependencies();
|
||||||
|
SortState state = SortStateScope.of(context);
|
||||||
|
_count.text = state.config.count.toString();
|
||||||
|
_duration.text = state.config.duration.inMicroseconds.toString();
|
||||||
|
_seed.text = state.config.seed.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
leading: BackButton(),
|
||||||
|
titleTextStyle: TextStyle(
|
||||||
|
color: Colors.black,
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
centerTitle: true,
|
||||||
|
title: Text('排序算法配置'),
|
||||||
|
),
|
||||||
|
body: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text('数据数量(个数):'),
|
||||||
|
const SizedBox(
|
||||||
|
width: 20,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: TextField(
|
||||||
|
controller: _count,
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text('时间间隔(微秒):'),
|
||||||
|
const SizedBox(
|
||||||
|
width: 20,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: TextField(
|
||||||
|
controller: _duration,
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text('随机种子:'),
|
||||||
|
const SizedBox(
|
||||||
|
width: 20,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: TextField(
|
||||||
|
controller: _seed,
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Spacer(),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
SortState state = SortStateScope.of(context);
|
||||||
|
state.config =state.config.copyWith(
|
||||||
|
count: int.parse(_count.text),
|
||||||
|
duration: Duration(
|
||||||
|
microseconds: int.parse(_duration.text),
|
||||||
|
),
|
||||||
|
seed: int.parse(_seed.text)
|
||||||
|
);
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
child: Text('确定设置'))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
60
lib/v5/pages/sort/views/data_painter.dart
Normal file
60
lib/v5/pages/sort/views/data_painter.dart
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class DataPainter extends CustomPainter{
|
||||||
|
|
||||||
|
final List<int> data;
|
||||||
|
|
||||||
|
DataPainter({required this.data});
|
||||||
|
|
||||||
|
@override
|
||||||
|
void paint(Canvas canvas, Size size) {
|
||||||
|
double itemWidth = size.width/data.length;
|
||||||
|
double height = size.height;
|
||||||
|
|
||||||
|
Paint paint = Paint();
|
||||||
|
paint.strokeWidth = itemWidth;
|
||||||
|
paint.strokeCap = StrokeCap.round;
|
||||||
|
|
||||||
|
for(int i=0;i<data.length;i++){
|
||||||
|
int value = data[i];
|
||||||
|
if (value < 1000 * .10) {
|
||||||
|
paint.color = Colors.blue.shade100;
|
||||||
|
} else if (value < 1000 * .20) {
|
||||||
|
paint.color = Colors.blue.shade200;
|
||||||
|
} else if (value < 1000 * .30) {
|
||||||
|
paint.color = Colors.blue.shade300;
|
||||||
|
} else if (value < 1000 * .40) {
|
||||||
|
paint.color = Colors.blue.shade400;
|
||||||
|
} else if (value < 1000 * .50) {
|
||||||
|
paint.color = Colors.blue.shade500;
|
||||||
|
} else if (value < 1000 * .60) {
|
||||||
|
paint.color = Colors.blue.shade600;
|
||||||
|
} else if (value < 1000 * .70) {
|
||||||
|
paint.color = Colors.blue.shade700;
|
||||||
|
} else if (value < 1000 * .80) {
|
||||||
|
paint.color = Colors.blue.shade800;
|
||||||
|
} else if (value < 1000 * .90) {
|
||||||
|
paint.color = Colors.blue.shade900;
|
||||||
|
} else {
|
||||||
|
paint.color = const Color(0xFF011E51);
|
||||||
|
}
|
||||||
|
canvas.drawLine(
|
||||||
|
Offset(i * itemWidth+itemWidth/2, 0),
|
||||||
|
Offset(
|
||||||
|
i * itemWidth+itemWidth/2,
|
||||||
|
size.height*(value/1000),
|
||||||
|
),
|
||||||
|
paint);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool shouldRepaint(covariant DataPainter oldDelegate) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
46
lib/v5/pages/sort/views/sort_bar.dart
Normal file
46
lib/v5/pages/sort/views/sort_bar.dart
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:iroute/components/components.dart';
|
||||||
|
|
||||||
|
import '../provider/state.dart';
|
||||||
|
import '../functions.dart';
|
||||||
|
import 'sort_button.dart';
|
||||||
|
|
||||||
|
class SortBar extends StatelessWidget {
|
||||||
|
const SortBar({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Row(
|
||||||
|
children: [
|
||||||
|
const SortButton(),
|
||||||
|
const SizedBox(width: 10,),
|
||||||
|
DropSelectableWidget(
|
||||||
|
fontSize: 12,
|
||||||
|
data: sortNameMap.values.toList(),
|
||||||
|
iconSize: 20,
|
||||||
|
height: 28,
|
||||||
|
width: 200,
|
||||||
|
disableColor: const Color(0xff1F425F),
|
||||||
|
onDropSelected: (int index) async {
|
||||||
|
SortState state = SortStateScope.of(context);
|
||||||
|
state.config =state.config.copyWith(
|
||||||
|
name: sortNameMap.keys.toList()[index]
|
||||||
|
);
|
||||||
|
// curveAnim = CurvedAnimation(
|
||||||
|
// parent: _ctrl, curve: maps.values.toList()[index]);
|
||||||
|
// _startAnim();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10,),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: (){
|
||||||
|
Scaffold.of(context).openEndDrawer();
|
||||||
|
// showDialog(
|
||||||
|
// useRootNavigator: false,
|
||||||
|
// context: context, builder: (ctx)=>AlertDialog());
|
||||||
|
},
|
||||||
|
child: const Icon(Icons.settings))
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
40
lib/v5/pages/sort/views/sort_button.dart
Normal file
40
lib/v5/pages/sort/views/sort_button.dart
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import '../provider/state.dart';
|
||||||
|
|
||||||
|
class SortButton extends StatelessWidget {
|
||||||
|
const SortButton({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
SortState state = SortStateScope.of(context);
|
||||||
|
VoidCallback? action;
|
||||||
|
IconData icon;
|
||||||
|
Color color;
|
||||||
|
switch (state.status) {
|
||||||
|
case SortStatus.none:
|
||||||
|
icon = Icons.not_started_outlined;
|
||||||
|
color = Colors.green;
|
||||||
|
action = state.sort;
|
||||||
|
break;
|
||||||
|
case SortStatus.sorting:
|
||||||
|
icon = Icons.stop_circle_outlined;
|
||||||
|
color = Colors.grey;
|
||||||
|
action = null;
|
||||||
|
break;
|
||||||
|
case SortStatus.sorted:
|
||||||
|
icon = Icons.refresh;
|
||||||
|
color = Colors.black;
|
||||||
|
action = state.reset;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: action,
|
||||||
|
child: Icon(
|
||||||
|
icon,
|
||||||
|
color: color,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
22
lib/v5/pages/sort/views/sort_page.dart
Normal file
22
lib/v5/pages/sort/views/sort_page.dart
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import '../provider/state.dart';
|
||||||
|
import 'data_painter.dart';
|
||||||
|
|
||||||
|
class SortPage extends StatelessWidget{
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
SortState state = SortStateScope.of(context);
|
||||||
|
List<int> numbers = state.data;
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
body: CustomPaint(
|
||||||
|
painter: DataPainter(data: numbers),
|
||||||
|
child: ConstrainedBox(constraints: BoxConstraints.expand()),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
18
pubspec.yaml
18
pubspec.yaml
@@ -28,21 +28,23 @@ environment:
|
|||||||
# the latest version available on pub.dev. To see which dependencies have newer
|
# the latest version available on pub.dev. To see which dependencies have newer
|
||||||
# versions available, run `flutter pub outdated`.
|
# versions available, run `flutter pub outdated`.
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
flutter_colorpicker: ^1.0.3
|
flutter_colorpicker: ^1.0.3
|
||||||
window_manager: ^0.3.7
|
window_manager: ^0.3.7
|
||||||
go_router: ^12.0.0
|
adaptive_navigation: ^0.0.4
|
||||||
|
go_router: ^10.1.0
|
||||||
|
provider: 6.0.5
|
||||||
|
url_launcher: ^6.0.7
|
||||||
|
equatable: ^2.0.5
|
||||||
|
url_strategy: ^0.2.0
|
||||||
|
quiver: ^3.1.0
|
||||||
|
path_to_regexp: ^0.4.0
|
||||||
# The following adds the Cupertino Icons font to your application.
|
# The following adds the Cupertino Icons font to your application.
|
||||||
# Use with the CupertinoIcons class for iOS style icons.
|
# Use with the CupertinoIcons class for iOS style icons.
|
||||||
cupertino_icons: ^1.0.2
|
cupertino_icons: ^1.0.2
|
||||||
|
toly_menu:
|
||||||
logging: ^1.0.0
|
path: E:\Projects\Flutter\packages\toly_menu
|
||||||
provider: 6.0.5
|
|
||||||
shared_preferences: ^2.0.11
|
|
||||||
url_launcher: ^6.0.7
|
|
||||||
adaptive_navigation: ^0.0.4
|
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
|
|||||||
|
|
||||||
FlutterWindow window(project);
|
FlutterWindow window(project);
|
||||||
Win32Window::Point origin(10, 10);
|
Win32Window::Point origin(10, 10);
|
||||||
Win32Window::Size size(640, 360);
|
Win32Window::Size size(1600, 1200);
|
||||||
if (!window.Create(L"iroute", origin, size)) {
|
if (!window.Create(L"iroute", origin, size)) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user