数据结构和算法对于不少前端工程师来讲,一直以为是无关紧要的,但其实否则,我的以为,前端工程师实际上是最须要重视数据结构和算法的人,由于前端所作的东西是用户访问网站第一眼看到的东西,特别在移动浪潮到来以后,对用户体验愈来愈高,对前端提出了更高的要求,面对愈来愈复杂的产品,须要坚实的数据结构和算法基础才能驾驭。
若是没有学习过计算机科学的程序员,当咱们在处理一些问题时,比较熟悉的数据结构就是数组,数组无疑是一个很好的选择。但不少时候,对于不少复杂的问题,数组就显得太过简陋了,当学习了数据结构和算法以后,对于不少编程问题,当想到一个合适的数据结构后,设计和实现解决这些问题的算法就手到擒来。html
相关讲解细分:
数据结构:列表、栈、队列、链表、字典、散列、图和二叉查找树
排序算法:冒牌排序、选择排序、插入排序、希尔排序、归并排序和快速排序
查找算法:顺序查找和二分查找前端
在平常生活中,人们常用列表:待办事项列表、购物清单、最佳十名榜单等等。而计算机程序也在使用列表,在下面的条件下,选择列表做为数据结构就显得尤其有用:git
反之,若是数据结构很是复杂,列表的做用就没有那么大了。程序员
栈是一种特殊的列表,栈内的元素只能经过列表的一端访问,这一端称为栈顶。想象一下,咱们日常在饭馆见到的一摞盘子就是现实世界常见的栈的例子,只能从最上面取盘子,盘子洗干净后,也只能放在最上面。栈被称为一种后入先出的数据结构。是一种高效的数据结构,由于数据只能在栈顶添加或删除,因此这样的操做很快。
使用条件:github
后入先出或先进后出
的原理,都优先考虑使用栈
队列也是一种列表,不一样的是队列只能在队尾插入元素,在队首删除元素。想象一下,咱们在银行排队,排在最前面的人第一个办理业务,然后面来的人只能排在队伍的后面,直到轮到他们为止。
使用条件:web
先进先出、后入后出
的原理,都优先考虑使用队列常见应用场景:算法
链表也是一种列表,为何须要出现链表,JavaScript中数组的主要问题时,它们被实现成了对象,与其余语言(好比C++和Java)的数组相对,效率很低。若是你发现数组在实际使用时很慢,就能够考虑使用链表来代替它。
使用条件:shell
一维数组
的状况中。若是须要随机访问,数组仍然是更好的选择。
字典是一种以键-值
对行驶存储数据的数据结构,JavaScript中的Object类就是以字典的形式设计的。JavaScript能够经过实现字典类,让这种字典类型的对象使用起来更加简单,字典能够实现对象拥有的常见功能,并相应拓展本身想要的功能,而对象在JavaScript编写中随处可见,因此字典的做用也异常明显了。编程
散列(也称为哈希表)是一种的经常使用的数组存储技术,散列后的数组能够快速地插入或取用。散列使用的数据结构叫作散列表。在散列表上插入、删除和取用数据
都很是快,但对于查找操做来讲却效率低下,好比查找一组数组中的最大值和最小值。这些操做须要求助于其余数据结构,好比下面介绍的二叉查找树。数组
散列表在JavaScript中能够基础数组去进行设计。数组的长度是预先设定的,全部元素根据和该元素对应的键,保存在数组的特定位置,这里的键和对象的键是类型的概念。使用散列表存储数组时,经过一个散列函数将键映射为一个数字,这个数字的范围是0到散列表的长度。
即便使用一个高效的散列函数,依然存在将两个键映射为同一个值得可能,这种现象叫作碰撞。常见碰撞的处理方法有:开链法
和线性探测法
(具体概念有兴趣的能够网上自信了解)
使用条件:
图由边的集合及顶点的集合组成。地图是咱们身边很常见的现实场景,好比每两个城镇都由某种道路相连。上面的每一个城镇能够看做一个顶点,链接城镇的道路即是边。边由顶点对(v1, v2)定义,v1和v2分别是图中的两个顶点。顶点也有权重,也成为成本。若是一个图的顶点对是有序的,则称之为有向图(例如常见的流程图),反之,称之为无序图。
使用场景(用图对现实中的系统建模):
搜索图的算法主要有两种: 深度优先搜索和广度优先搜索。
树是计算机科学中常常用到的一种数据结构。树是一种非线性的数据结构,以分层的方式存储数据。
二叉树每一个节点的子节点不容许超过两个。一个父节点的两个子节点分别称为左节点和右节点,经过将子节点的个数限定为2,能够写出高效的程序在树中插入、查找和删除数据
。
二叉查找树(BST)是一种特殊的二叉树,相对较小的值保存在左节点中,较大的值保存在右节点中。这一特性使得查找的效率很高
,对于数值型和非数值型的数据,好比单词和字符串,都是如此。
二叉查找树实现方法
function Node(data, left, right) { // 建立节点
this.data = data;
this.left = left;
this.right = right;
this.show = show
}
function show () { // 显示树的数据
return this.data
}
function BST () { // 二叉查找树类
this.root = null;
this.insert = insert;
this.inOrder = inOrder; // inOrder是遍历BST的方式
}
function insert (data) { // 向树中插入数据
var n = new Node(data, null, null)
if (this.root == null) {
this.root = n;
} else {
var current = this.root;
var parent;
while (true) {
parent = current
if (data < current.data) {
current = current.left;
if (current == null) {
parent.left = n;
break;
}
} else {
current = current.right;
if (current == null) {
parent.right = n;
break;
}
}
}
}
}
基本排序算法,其核心思想是指对一组数组按照必定的顺序从新排列。从新排列时用到的技术是一组嵌套的for循环。其中外循环会遍历数组的每一项,内循环则用于比较元素。
冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,若是它们的顺序错误就把它们交换过来。走访数列的工做是重复地进行直到没有再须要交换,也就是说该数列已经排序完成。这个算法的名字由来是由于越小的元素会经由交换慢慢“浮”到数列的顶端。
function bubbleSort (arr) {
var i = arr.length;
while (i > 0) {
var pos = 0
for (var j = 0; j < i; j++) {
if (arr[j] > arr[j+1]){
pos = j
var temp = arr[j]
arr[j] = arr[j+1]
arr[j+1] = temp
}
}
i = pos
}
return arr
}
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(bubbleSort(arr));//[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
选择排序(Selection-sort)是一种简单直观的排序算法。它的工做原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,而后,再从剩余未排序元素中继续寻找最小(大)元素,而后放到已排序序列的末尾。以此类推,直到全部元素均排序完毕。
function selectionSort (arr) {
var len = arr.length;
var minIndex, temp;
for (var i = 0; i < len-1; i++) {
minIndex = i;
for (var j = i+1; j < len; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j
}
}
temp = arr[minIndex]
arr[minIndex] = arr[i]
arr[i] = temp
}
return arr
}
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(selectionSort(arr));//[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
插入排序(Insertion-Sort)的算法描述是一种简单直观的排序算法。它的工做原理是经过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,一般采用in-place排序(即只需用到O(1)的额外空间的排序),于是在从后向前扫描过程当中,须要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。
function insertSort (arr) {
var len = arr.length
for (i = 1; i < len; i++) {
var key = arr[i]
var j = i - 1
while (j >= 0 && arr[j] > key) {
arr[j+1] = arr[j]
j--;
}
arr[j+1] = key
}
return arr
}
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(insertSort(arr));//[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
高级数据排序算法,一般用于处理大型数据集的最高效排序算法,它们处理的数据集能够达到上百万个元素,而不只仅是几百个或者几千个,下面咱们将介绍希尔排序、归并排序和快速排序。
1959年Shell发明,第一个突破O(n^2)的排序算法;是简单插入排序的改进版;它与插入排序的不一样之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增量排序。
希尔排序的核心在于间隔序列的设定。既能够提早设定好间隔序列,也能够动态的定义间隔序列。
function shellSort (arr) {
var len = arr.length;
var temp, gap = 1;
while (gap < len /3 ) {
gap = gap * 3 + 1
}
while (gap >= 1) {
for (var i = gap; i < len; i++) {
temp = arr[i]
for (var j = i - gap; j >= 0 && arr[j] > temp; j-=gap) {
arr[j+gap] = arr[j]
}
arr[j+gap] = temp
}
gap = (gap - 1) / 3
}
return arr
}
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(shellSort(arr));//[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
归并排序是创建在归并操做上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个很是典型的应用。归并排序是一种稳定的排序方法。将已有序的子序列合并,获得彻底有序的序列;即先使每一个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。
function mergeSort (arr) {
var len = arr.length
if (len < 2) {
return arr
}
var middle = Math.floor(len / 2)
var left = arr.slice(0, middle)
var right = arr.slice(middle)
return merge (mergeSort(left), mergeSort(right));
}
function merge (left, right) {
var result = []
while (left.length && right.length) {
if (left[0] < right[0]) {
result.push(left.shift())
} else {
result.push(right.shift())
}
}
while (left.length) {
result.push(left.shift())
}
while (right.length) {
result.push(right.shift())
}
return result
}
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(mergeSort(arr));
快速排序是处理 大数据集最快的排序算法之一。它是一种分而治之的算法,经过递归的方法将数据依次分解为包含较小元素和较大元素的不一样子序列。该算法不断重复这个步骤知道全部数据都是有序的。
这个算法首先要在列表中选择一个元素做为基准值。数据排序围绕基准值进行,将列表中小于基准值的元素移到数组的底部,将大于基准值的元素移到数组的顶部。
function qSort (arr) {
if (arr.length == 0) {
return []
}
var left = []
var right = []
var pivot = arr[0]
for (var i = 1; i < arr.length; i++) {
if (arr[i] < pivot) {
left.push(arr[i])
} else {
right.push(arr[i])
}
}
return qSort(left).concat(pivot, qSort(right))
}
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(qSort(arr));
在列表中查找数据有两种方式:顺序查找和二分查找。顺序查找适用于元素随机排列的列表;二分查找适用于元素已排序的列表。二分查找效率更高,可是必须在进行查找以前花费额外的时间将列表中的元素排序。
对于查找数据,最简单的方法就是从列表的第一个元素开始对列表元素逐个进行判断,直到找到了想要的结果,或者直到列表结尾也没有找到。这种方法称为顺序查找,有时也被称为线性查找。
function seqSearch (arr, data) {
for (var i = 0; i < arr.length; i++) {
if (arr[i] == data) {
return i;
}
}
return -1;
}
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(seqSearch(arr, 15))
二分法查找,也称折半查找,是一种在有序数组中查找特定元素的搜索算法。查找过程能够分为如下步骤:
function binSearch (arr, data) {
var low = 0;
var high = arr.length - 1
while (low <= high) {
var middle = Math.floor((low + high) / 2)
if (arr[middle] < data) {
low = middle + 1
} else if (arr[middle] > data) {
high = middle - 1
} else {
return middle
}
}
return -1
}
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(binSearch(arr, 15))
持续更新中。。。。。。