《数据结构》课程设计-排序算法可视化

《数据结构》课程设计-js实现排序算法可视化

先上效果图:
在这里插入图片描述

一.数据可视化

1.什么是数据可视化

数据可视化主要旨在借助于图形化手段,清晰有效地传达与沟通信息。但是,这并不就意味着数据可视化就一定因为要实现其功能用途而令人感到枯燥乏味,或者是为了看上去绚丽多彩而显得极端复杂。为了有效地传达思想概念,美学形式与功能需要齐头并进,通过直观地传达关键的方面与特征,从而实现对于相当稀疏而又复杂的数据集的深入洞察。然而,设计人员往往并不能很好地把握设计与功能之间的平衡,从而创造出华而不实的数据可视化形式,无法达到其主要目的,也就是传达与沟通信息。
数据可视化与信息图形、信息可视化、科学可视化以及统计图形密切相关。当前,在研究、教学和开发领域,数据可视化乃是一个极为活跃而又关键的方面。“数据可视化”这条术语实现了成熟的科学可视化领域与较年轻的信息可视化领域的统一。

2.什么时候需要将数据可视化

你的程序有多么依赖数据?即使应用程序不完全面向业务,你也可能需要管理面板、仪表板、性能跟踪以及用户非常喜欢的类似分析功能的数据。

对于 JS 开发人员来说,可视化数据的能力与制作交互式网页一样有价值。特别是两者经常同时出现。

我们利用视觉获取的信息量,远远比别的感官要多的多

将数据转换成图形,能给客户更大的视觉冲击以及更好的体验

3.如何将数据可视化

作为以“成为Java全栈工程师”为目标而拼命前进的人,数据可视化特指web前端的数据可视化。随着JavaScript在数据可视化领域的活跃,市面上出现了众多可视化框架,如:D3.js、hightcharts.js、echarts.js…………

我选择了14个用于数据可视化的 JavaScript 库(这些库目前是最受欢迎或最有趣的),看看哪个最适合我们的项目。在这里要考虑许多因素:

  • 我想要什么样的图表?饼图,地理图,折线图, 条形图?
  • 有些库只支持少数几种类型。首先要知道自己到底需要哪些。
  • 数据集有多大?
  • 基于 SVG 的库通常更适合中小型数据集,因为每个元素都是唯一的节点并存在于 DOM 树中。这也意味着它们允许被直接访问,从而具有更多的灵活性。虽然你可以借助一些数据聚合算法、智能内存管理和其他花哨的技巧使它们能够处理大型数据集,但是使用基于 Canvas 的大型数据集工具是更可靠的选择。Canvas 非常快。
  • 该应用是用于Web端、移动端还是两者兼而有之?
  • 有些库在响应性方面更好,而其他一些库有自己的 React Native 版本,如 Victory。
  • 浏览器支持给定的库吗?
  • 你使用哪种 JavaScript 框架?
  • 确保你的数据库库能够顺利运行。如果你在用 React,那么使用特定于 React 的库可能比使用包装器更好。
  • 你需要什么样的外观?
  • 如果你需要一些高级动画,也应该考虑到这一点。

在某些情况下,你可能根本不需要数据可视化库。有时用原生 JavaScript 从头开始编写是个好主意。虽然开始代价很大(特别是在你第一次这样的时候),但对于那些带有自定义定制图表的项目来说,可能会在未来获得回报。

那么什么情况下使用库?

当你的项目中有一个奇怪的图表,一个需要漂亮的界面基本功能,有所有的花里胡哨(工具提示、图例、X/Y 轴等)的东西,或当应用需要标准化、响应和详细的图表,特别是需要有多种类型时。

最后,我们用库来避免一次又一次地重新发明轮子,并且大多数库已经存在了很久,并考虑到了大多数的使用情况。对了,他们也带有内置的动画效果。

在项目中尝试所有这些库是不可能的,下面是我根据自己和其他人的经验列出的的列表。请记住,在深入了解一个库之前,搞清楚怎样把它集成到你的项目中总是一个好主意。最后,选哪个是你的事 —— 这只是一个清单!

4.免费数据可视化库

如果你不是一家大公司,那么开源库提供的选择就足够多了。加入你能够回答我上面提到的问题,会很容易找到完美的匹配。

1、D3.js

D3 是最受欢迎的 JS 库之一,不仅可用于数据可视化,还包括动画、数据分析、地理和数据实应用。使用HTML,SVG 和 CSS 等技术。它有一堆庞大的 API,有些人认为它根本不是数据可视化库 。凡是你能想到的,都可以通过这个库完成,但它也有其缺点,学习曲线非常陡峭,而且文档已经过时,这很容易导致混乱。

大部分 API 都暴露了对 DOM 的直接访问,这可能与 React 或 Vue 等现代前端框架的工作方式产生冲突。但还是有办法解决这个问题的。有一份声明性数据驱动文档(简称d4)建议让框架操纵 DOM 并严格使用 D3 作为数据 API。你可以在这里找到更多信息和例子

适用于:任何环境

GitHub:https://github.com/d3
演示:https://github.com/d3/d3/wiki…

2、Recharts

为 React 专用。 Recharts 在使用 D3 作为引擎,并导出了声明性组件。它非常轻巧,可以通过渲染 SVG 元素来创建漂亮的交互式图表。它易于使用而且文档完整。图表是可自定义的,库本身提供了一些很好的例子。它的静态图表性能表现非常出色,并包含内置的通用图表工具,比如:图例工具提示和标签。在同一页面和大型数据集上处理多个动画图表时可能会出现滞后现象,不过它仍适用于大多数应用场合。

有点令人不安的是在 GitHub 上有大量未解决的问题。这些问题可能并不重要,但作者似乎并不是很热血回答这些问题。所以如果你遇到困难,请做好深入研究代码的准备。

适用于:React
GitHub:https://github.com/recharts
例子:http://recharts.org/en-US/exa…

3、Victory

这是一组专为 React 和 React Native 设计的模块化图表组件。 Victory 在基础方面做得很好 —— 例如坐标轴定制、标签、为单个图表传递不同的数据集都非常简单,并且对样式和行为进行调整时非常简单直观。它真的很好用,能让你用最少的代码创建漂亮的图表。这是绝对值得一试的跨平台的库。

适用于:React,React Native

GitHub:https://github.com/Formidable…
演示:https://formidable.com/open-s…

4、React-vis

这是 Uber 开发的一个简单的可视化库,它允许你创建所有常用的图表类型:条形图,树形图,折线图,面积图等。它的 API 非常简单,而且非常灵活。它很轻量,动画简单但流畅。还允许基于现有元素编写自定义图表。

然而,它极简主义的造型可能并不适合每个人的口味(但我喜欢它!)。虽然反响平平,但其文档简单易读。

适用于:React

GitHub:https://uber.github.io/react-…
例子:https://uber.github.io/react-…

5、ApexCharts

这是一个相当简洁的 SVG 图表库,还附带 Vue.js 和 React 包装器。它在不同设备上的效果看起来都很不错,而且该库允许自定义徒步,并提供全面的文档。在较大的数据集上性能可能会受到影响,因此请确保它确实适合你的项目。根据 ApexCharts 的作者 Juned Chhipa 的说法,该库是为了更容易缩放、平移、滚动数据、在图表上放置信息性注释等目的而写的。

这个库比较新,还有很大的发展空间,但如果响应性和互动性对你来说特别重要,那么这个漂亮的库是值得一试的!

适用于:React,Vue.js,纯 JavaScript

GitHub:https://github.com/apexcharts
例子:https://apexcharts.com/javasc…

6、Chart.js

一个非常受欢迎的开源库,在GitHub上超过 4 万 star。它是轻量级的,允许你用 HTML5 Canvas 元素构建响应式图表。可以轻松地对折线图和条形图进行混合和匹配以组合不同的数据集,这是非常棒的功能。

Chart.js 默认为你提供六种不同的图表类型,它支持响应式,并且对初学者非常友好。它也是我处理大数据集时的首选库。绝对是最有趣的开源库之一。

适用于:React,Vue.js

GitHub:https://github.com/chartjs/Ch…
例子:https://www.chartjs.org/sampl…

7、Echarts

百度创建的这个库对于 Web 的数据可视化非常有用。它也提供英文版本,适用于大数据集。它还支持 SVG 和 Canvas 渲染。

适用于:所有环境

GitHub:https://github.com/ecomfe/ech…
例子:https://ecomfe.github.io/echa…

8、Frappe Charts

这是一个非常简单的库,用于零依赖关系的图表。它是开源的,只有 17 个贡献者,是本列表中最小的库之一。

Frappe Charts 的灵感来自一个类似 GitHub 视觉效果的软件包,支持折线图,条形图和其他类型的图表。如果你正在找一个小巧轻量的包,这就是其中一个!

适用于:任何环境

GitHub:https://github.com/frappe/charts
官网:https://frappe.io/charts

9、Nivo

Nivo 是一个基于 D3 和 React 的漂亮框架,提供十四种不同类型的组件来呈现你的数据。它于 2017 年发布,在2017 年 8 月 20 日作为 ProductHunt 的产品推出。

Nivo 提供了许多自定义选项和三个渲染选项:Canvas,SVG,甚至基于 API 的HTML。它的文档非常出色,Demo 可配置且有趣。这是一个高级库,非常简单,不过提供自定义可视化的余地很小。

适用于:React

GitHub:https://github.com/plouc/nivo
官网:https://nivo.rocks/

10、Google Charts

一个非常流行的图表Web服务,我根本无法把它从列表中删除。对于许多人来说,它是首选的 JS 库,因为它提供了多种预先构建的图表类型,例如条形图、折线图、区域图、日历图、地理图表等等。然而,对我来说,在大多数情况下,这个库有点过分,坦率地说我不建议使用它。

它是免费的,但不是开源的(和每个 Google 产品一样)。它在默认情况下不是响应式的,但你可以使用代码调整图表大小。根据图表类型,有不同的自定义选项,它并不完全适合初学者。而且你必须直接从 Google URL 而不是 NPM 包加载它。

适用于:任何环境

Google Charts 官网:https://developers.google.com…
文档:https://developers.google.com…

5.商业图表库

有些库为个人提供了免费版,但你需要付费才能在商业应用中使用它们。下面列出的都是大公司常用的。因为它们都是真正全面的、可定制的,并提供了很好的客户支持。如果你是一个企业,你应该检查出来。

11、amCharts

这是最热门的图表库之一。它漂亮设计确实能够使它在竞争中脱颖而出。 苹果、亚马逊、美国宇航局和许多知名公司都是 amCharts 的用户,这是非常令人印象深刻的。

amCharts 是一种商业工具,每个网站许可的起价为 180 美元。作为投入的回报,你可以获得所需的所有类型的图表,包括地理地图和出色的用户支持,平均响应时间少于3小时。这对大公司来说是一个很好的解决方案。

适用于:Angular,React,Vue.js,普通JS应用,TypeScript

GitHub:https://github.com/amcharts/a…
官网:https://www.amcharts.com/

12、CanvasJS

这是另一种商业工具,提供能够跨设备和浏览器的精美图表。不过它缺少一些图表类型,例如网络图表、迷你图和仪表图。此外它的学习曲线非常陡峭。

另一方面,即使有多达 100k+ 的数据点,也非常的快,并且工作流畅。提供了四个默认主题,应该能够适合大多数场景。他们的客户名单也令人印象深刻:Apple、博世、西门子、惠普、微软等。

适用于:Angular,React,jQuery,纯 JavaScript

官网:https://canvasjs.com/
演示:https://canvasjs.com/javascri…

13、Highcharts

一个发布于 2009 年的 JS 库,基于 SVG ,支持旧版浏览器的 VML 和 Canvas。 它提供了不同的项目模板。 Highcharts 能够与旧版浏览器兼容,其中包括 Internet Explorer 6。

对于非开发人员来说,这是一个很好的解决方案,因为它有一个集成的 WYSIWYG(所见即所得)图表编辑器。它的学习曲线非常流畅,并被许多主要参与者使用,如 Facebook 或微软 —— 甚至有人声称世界上最大的 100 家公司中有 72 家曾经使用过它。这是一个付费的解决方案,价格为1500美元,无限制的商业许可证。

然而在光鲜的外表之下,感觉就像它是在 2009 年写的。最近我的一位同事带我体验了它,让我告诉你,这并不是很愉快。当你不是在深入到代码层摆弄它时,它很好用,但是当你想要。。。这是一件苦差事。

适用于:任何环境

GitHub:https://github.com/highcharts…
官网:https://www.highcharts.com/

14、Zoomcharts

另一个商业 JS 数据工具,自称为 “世界上最具交互性的 JavaScript 图表库。” 除了反应灵敏之外,它主要关注多点触控手势和在各种设备上的原生感觉。该库自诩为美观的可视化,只需很少的代码就可以轻松地部署在你的产品中。
Zoomchatrts 是基于 Canvas 的,在相同的数据量下,使用默认设置,它的速度比基于 SVG 的竞争对手快20倍。我找不到 Zoomcharts 的确切价格,但我发现有一些评论称它 “价格昂贵”。但无论价格怎样,作为回报,你都会得到惊人的互动性、多点触控手势和高品质的用户支持。

适用于:任何环境

官网:https://zoomcharts.com/en/
Demo:https://zoomcharts.com/en/jav…

二.常见的排序算法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZgfmM4fA-1591885120158)(…/images/image-20200601175024501.png)]

1.冒泡排序

最简单的一种排序算法。假设长度为n的数组arr,要按照从小到大排序。则冒泡排序的具体过程可以描述为:首先从数组的第一个元素开始到数组最后一个元素为止,对数组中相邻的两个元素进行比较,如果位于数组左端的元素大于数组右端的元素,则交换这两个元素在数组中的位置,此时数组最右端的元素即为该数组中所有元素的最大值。接着对该数组剩下的n-1个元素进行冒泡排序,直到整个数组有序排列。算法的时间复杂度为O(n^2)。

在这里插入图片描述

2.选择排序

严蔚敏版《数据结构》中对选择排序的基本思想描述为:每一趟在n-i+1(i=1,2,…,n-1)个记录中选取关键字最小的记录作为有序序列中第i个记录。具体来说,假设长度为n的数组arr,要按照从小到大排序,那么先从n个数字中找到最小值min1,如果最小值min1的位置不在数组的最左端(也就是min1不等于arr[0]),则将最小值min1和arr[0]交换,接着在剩下的n-1个数字中找到最小值min2,如果最小值min2不等于arr[1],则交换这两个数字,依次类推,直到数组arr有序排列。算法的时间复杂度为O(n^2)。

3.插入排序

插入排序的基本思想就是将无序序列插入到有序序列中。例如要将数组arr=[4,2,8,0,5,1]排序,可以将4看做是一个有序序列(图中用蓝色标出),将[2,8,0,5,1]看做一个无序序列。无序序列中2比4小,于是将2插入到4的左边,此时有序序列变成了[2,4],无序序列变成了[8,0,5,1]。无序序列中8比4大,于是将8插入到4的右边,有序序列变成了[2,4,8],无序序列变成了[0,5,1]。以此类推,最终数组按照从小到大排序。该算法的时间复杂度为O(n^2)。

4.希尔排序

希尔排序(Shell’s Sort)在插入排序算法的基础上进行了改进,算法的时间复杂度与前面几种算法相比有较大的改进。其算法的基本思想是:先将待排记录序列分割成为若干子序列分别进行插入排序,待整个序列中的记录"基本有序"时,再对全体记录进行一次直接插入排序。

5.快速排序

快速排序的基本思想是:通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,已达到整个序列有序。一趟快速排序的具体过程可描述为:从待排序列中任意选取一个记录(通常选取第一个记录)作为基准值,然后将记录中关键字比它小的记录都安置在它的位置之前,将记录中关键字比它大的记录都安置在它的位置之后。这样,以该基准值为分界线,将待排序列分成的两个子序列。

一趟快速排序的具体做法为:设置两个指针low和high分别指向待排序列的开始和结尾,记录下基准值baseval(待排序列的第一个记录),然后先从high所指的位置向前搜索直到找到一个小于baseval的记录并互相交换,接着从low所指向的位置向后搜索直到找到一个大于baseval的记录并互相交换,重复这两个步骤直到low=high为止。

6.归并排序

“归并”的含义是将两个或两个以上的有序序列组合成一个新的有序表。假设初始序列含有n个记录,则可以看成是n个有序的子序列,每个子序列的长度为1,然后两两归并,得到(表示不小于x的最小整数)个长度为2(或者是1)的有序子序列,再两两归并。如此重复,直到得到一个长度为n的有序序列为止。这种排序方法称为2-路归并排序。

7.堆排序

  • 堆的概念
    堆:本质是一种数组对象。特别重要的一点性质:任意的叶子节点小于(或大于)它所有的父节点。对此,又分为大顶堆和小顶堆,大顶堆要求节点的元素都要大于其孩子,小顶堆要求节点元素都小于其左右孩子,两者对左右孩子的大小关系不做任何要求。
    利用堆排序,就是基于大顶堆或者小顶堆的一种排序方法。下面,我们通过大顶堆来实现。

  • 基本思想:
    堆排序可以按照以下步骤来完成:

    1. 首先将序列构建称为大顶堆;
      (这样满足了大顶堆那条性质:位于根节点的元素一定是当前序列的最大值)

在这里插入图片描述

 构建大顶堆.png
  1. 取出当前大顶堆的根节点,将其与序列末尾元素进行交换;
    (此时:序列末尾的元素为已排序的最大值;由于交换了元素,当前位于根节点的堆并不一定满足大顶堆的性质)

  2. 对交换后的n-1个序列元素进行调整,使其满足大顶堆的性质;

在这里插入图片描述

  1. 重复2.3步骤,直至堆中只有1个元素为止

三.程序设计

JavaScript实现各种排序

1.冒泡排序
function bubbleSort(arr) {
   
  var i = arr.length, j;
  var tempExchangVal;
  while (i > 0) {
   
    for (j = 0; j < i - 1; j++) {
   
      if (arr[j] > arr[j + 1]) {
   
        tempExchangVal = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = tempExchangVal;
      }
    }
    i--;
  }
  return arr;
}
var arr = [3, 2, 4, 9, 1, 5, 7, 6, 8];
var arrSorted = bubbleSort(arr);
console.log(arrSorted);
alert(arrSorted);
2.选择排序
var arr = new Array(1, 3, 2, 8, 9, 1, 5);
function SelectionSort(arr) {
   
    if (arr == null || arr.length < 2) {
   
         return arr;
    }
    for (var i = 0; i < (arr.length - 1); i++) {
   
        let minIndex = i;
        for (let j = i + 1; j < arr.length; j++) {
   
            minIndex = arr[j] < arr[minIndex] ? j : minIndex;
        }
        let temp = arr[i];
        arr[i] = arr[minIndex];
        arr[minIndex] = temp;
    }
    return arr;
}
console.log(arr);
SelectionSort(arr);
console.log(arr);
3.插入排序
function InsertionSort(array) {
   
  var length = array.length;
  for (var i = 0; i < length - 1; i++) {
   
    //i代表已经排序好的序列最后一项下标
    var insert = array[i+1];
    var index = i + 1;//记录要被插入的下标
    for (var j = i; j >= 0; j--) {
   
      if (insert < array[j]) {
   
        //要插入的项比它小,往后移动
        array[j+1] = array[j];
        index = j;
      }
    }
    array[index] = insert;
    console.log(array);
  }
  return array;
}

var arr = [100,90,80,62,80,8,1,2,39];
var result = InsertionSort(arr);
console.log(result);
4.希尔排序
function ShellSort(array) {
   
  var length = array.length;
  var gap = Math.round(length / 2);
  while (gap > 0) {
   
    for (var i = gap; i < length; i++) {
   
      var insert = array[i];
      var index = i;
      for (var j = i; j >= 0; j-=gap) {
   
        if (insert < array[j]) {
   
          array[j+gap] = array[j];
          index = j;
        }
      }
      array[index] = insert;
    }
    console.log(array);
    console.log("-----------------------");
    gap = Math.round(gap/2 - 0.1);
  }
  return array;
}
 
var arr = [ 13, 14, 94, 33, 82, 25, 59, 94, 65, 23, 45, 27, 73, 25, 39, 10 ];
var result = ShellSort(arr);
console.log(result); 
5.快速排序
function QuickSort(array) {
   
  var length = array.length;
  if (length <= 1) {
   
    return array;
  } else {
   
    var smaller = [];
    var bigger = [];
    var base = [array[0]];
    for (var i = 1; i < length; i++) {
   
      if (array[i] <= base[0]) {
   
        smaller.push(array[i]);
      } else {
   
        bigger.push(array[i]);
      }
    }
    console.log(smaller.concat(base.concat(bigger)));
    console.log("-----------------------");
    return QuickSort(smaller).concat(base.concat(QuickSort(bigger)));
  }
}
 
 
var arr = [ 8, 10, 100, 90, 65, 5, 4, 10, 2, 4 ];
var result = QuickSort(arr);
console.log(result);
6.归并排序
function MergeSort(array) {
   
  var length = array.length;
  if (length <= 1) {
   
    return array;
  } else {
   
    var num = Math.ceil(length/2);
    var left = MergeSort(array.slice(0, num));
    var right = MergeSort(array.slice(num, length));
    return merge(left, right);
  }
}
 
function merge(left, right) {
   
  console.log(left);
  console.log(right);
  var a = new Array();
  while (left.length > 0 && right.length > 0) {
   
    if (left[0] <= right[0]) {
   
      var temp = left.shift();
      a.push(temp);
    } else {
   
      var temp = right.shift();
      a.push(temp);
    }
  }
  if (left.length > 0) {
   
    a = a.concat(left);
  }
  if (right.length > 0) {
   
    a = a.concat(right);
  }
  console.log(a);
  console.log("-----------------------------");
  return a;
}
 
var arr = [ 13, 14, 94, 33, 82, 25, 59, 94, 65, 23, 45, 27, 73, 25, 39, 10 ];
var result = MergeSort(arr);
console.log(result);
7.堆排序
/*
维护最大堆性质
@param arr 数组
@param index 元素下标
@param heapSize 堆大小
*/
function maxHeap(arr, index, heapSize){
   
  var tem = index; //记录入参元素下标
  var leftChildIndex = 2 *i ndex + 1; //元素的左子树的元素下标
  var rightChildeIndex = 2 * index + 2;//元素的右子树的元素下标
  if( leftChildIndex < heapSize && arr[leftChildIndex] > arr[index]){
   
    index = leftChildIndex;
  }
  if( rightChildeIndex < heapSize && arr[rightChildeIndex] > arr[index]){
   
    index = rightChildeIndex;
  }
  if(index != tem){
   
    var t = arr[tem];
    arr[tem] = arr[index];
    arr[index] = t;
    maxHeap(arr, index, heapSize);
  }
}
/*
构建最大堆
@param arr 数组
*/
function buildMaxHeap(arr){
   
  var lastFather = Math.floor(arr.length / 2) - 1;//堆的最后一个父节点
  for(var i = lastFather; i > 0; i --){
   
    maxHeap(arr, i, arr.length);
  }
}
/*
堆排序
&
  • 5
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值