个人认为数据结构有点偏向理论知识点,从这些理论知识点,我们可以知道各种数据结构的特点,然后在特定的场景下使用对应的数据结构来存储。
从逻辑上来说基础的数据结构只有线性结构、非线性结构,也就是数组、链表
。其他复杂一点的如队列、栈、树、图、hash table
都可以通过数组和链表的方式来存储。
有了数组、链表为什么还要有其他数据结构?
我的理解是出现队列、栈、树、图
等数据结构的原因,是为了解决,部分问题处理过程中时间复杂度过高的问题,如我们在数组中如果想要更快的访问到先push 进去的数据,那么我们直接用队列即可。
我们通常说的数据结构是逻辑上数据与数据相互之间存在一种或多种关系的数据元素集合
。
算法是解决某种具体问题的方法、步骤
。
数据结构是静态
的,它只是组织数据的一种方式,如果不在它的基础上操作、构建算法,孤立存在的数据结构就是没用的、也没有意义。
数据结构和算法是相辅相成
的。数据结构是为算法服务的,算法要作用在特定的数据结构之上。
如当我们把数据存入数组中,有个需求我们需要把按照小到大排序展现出来,我们可以一个一个的比较(冒泡排序)。但是当数据量很大的时候,这种方法就很低效了,这个时候我们可以使用快排这样的算法。
前面说算法是作用在特定的数据结构之上,在大部分的时候我们都是使用别人总结出来的一些方法、思想如:
排序是一个很常见的需求,我们可以通过冒泡、或者快排来解决。
冒泡:
const bubbleSort = (arr) => {
if (arr.length <= 1) return
for (let i = 0; i < arr.length; i++) {
let hasChange = false
for (let j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
const temp = arr[j]
arr[j] = arr[j + 1]
arr[j + 1] = temp
hasChange = true
}
}
// 如果false 说明所有元素已经到位
if (!hasChange) break
}
console.log(arr)
}
递归版快排:
function quickSort (arr) {
if (arr.length < 2) return arr
let pivot = arr[0]
let left = arr.slice(1).filter(t => t <= pivot)
let right = arr.slice(1).filter(t => t > pivot)
return [...quickSort(left), pivot, ...quickSort(right)]
}
递归的层级过多有可能造成内存泄露的风险,下面是优化之后的,在原数组中移动的快速排序。
原数组移动快排:
function quickSort2 (arr, left, right) {
if (left < right) {
let index = partition(arr, left ,right)
// index 已经是正确的位置
quickSort2(arr, left, index - 1)
quickSort2(arr, index + 1, right)
}
return arr
}
// 分区:把基准值插入到正确的位置
function partition (arr, left, right) {
let pivot = arr[left]
let index = left + 1 // 待交换位置为左边+1
// 左 ---> 右扫描
for (let i = index; i <= right; i++) {
// 小 ----> 大 小于放左边
if (arr[i] <= pivot) {
swap(arr, index, i)
index++
}
}
// 最后把基准值插入到合适的位置
swap(arr, left, index -1 )
return index - 1;
}
function swap (arr, i, j) {
[arr[i], arr[j]] = [arr[j], arr[i]]
}
let list = [66,1,434,545,65,0,2,3,6,66,999,-1,22]
let arr = quickSort2(list,0,list.length)
console.log(arr)
还有很多的排序如插入排序、归并排序等可以自行了解。
数据结构、设计模式、网络这些还是挺重要的。
路漫漫其修远兮,吾将上下而求索。