排序算法
冒泡排序O(n^2)
前往后后依次比较相邻两个元素大小,大的元素往后挪,比较完第一遍后,最大的元素排到了数组的最后一位
- 从第1个数字比较与最后一个数字,结束时最大的位于最后;
- 第二轮比较到倒数第二个
- …
- 最后一轮比较第1,2个;
mSort(arr);
function mSort(a){
for(var i=0;i< a.length;i++){
for(var j=i;j< a.length;j++){
if(a[j]<a[i]){
var temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
}
console.log(a);
}
快速排序O(nlog(n))
快速排序的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据比另一部分的所有数据要小,再按这种方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,使整个数据变成有序序列。
- 取出中间一个数centernum(原数组不保留)
- 比centernum小的放入数组left,比centernum大的放入right数组
- left right 进行快速排序递归
- arr=left+centernum+right
qSort(arr);
function qSort(a){
if(a.length<2){
return;
}
var left=[];
var right=[];
//找中间索引centerIndex 取出中间数centerNum
var centerIndex=a[parseInt(a.length/2)];
var centerNum=a.splice(centerIndex,1);
for(var i=0;i< a.length;i++){
//a[i]<=centernum 放入数组left,a[i]>centernum放入right数组
if(a[i]<=centerNum){
left.push(a[i]);
}else{
right.push(a[i]);
}
}
return qSort(left).concat(centerNum).concat(qSort(right));
console.log(arr);
}
插入排序O(n^2)
插入排序的基本操作:将一个数据插入到已经排好序的有序数据中。
- 从第i(2)个数开始插入排序
- 逆序与前面所有的数(i-1~1)进行比较,小的数互换到前面去
算法适用于少量数据的排序
insertSort(arr);
function insertSort(a){
//从第i个数插入排序
for(var i=1 ;i<a.length;i++){
//与i-1往前比较,a[i]<a[j]互换
for(var j=i-1;j>=0;j--){
if(a[j]>a[i]){
var temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
}
console.log(arr);
}
选择排序O(n^2)
在要排序的一组数中,选出最小的一个数与第一个位置的数交换;然后在剩下的数当中再找最小的与第二个位置的数交换,如此循环到倒数第二个数和最后一个数比较为止(假设为从小到大排序)
- 对数组中所有数值进行比较,获得最小值下标,然后将最小值与第一个数交换
- 对数组中剩余(除第一个数)数值进行比较,获得最小值下标,然后将最小值与第二个数交换
- 直至确定倒数第二个位置的数值
seleSort(arr);
function seleSort(a){
for (var i=0;i< a.length;i++){
var minNum=a[i];
for(var j=i;j< a.length;j++){
if(a[j]<a[i]){
minNum=a[j];
a[j]=a[i];
a[i]=minNum
}
}
}
console.log(a);
}
算法复杂度
大O表示法的概念。是描述算法的性能和复杂程度。
数据结构
栈
栈是一种遵从先进后出 (LIFO) 原则的有序集合;新添加的或待删除的元素都保存在栈的末尾
class Stack {
constructor() {
this.items = []
}
// 入栈
push(element) {
this.items.push(element)
}
// 出栈
pop() {
return this.items.pop()
}
// 末位
get peek() {
return this.items[this.items.length - 1]
}
// 是否为空栈
get isEmpty() {
return !this.items.length
}
// 尺寸
get size() {
return this.items.length
}
// 清空栈
clear() {
this.items = []
}
// 打印栈数据
print() {
console.log(this.items.toString())
}
}
队列
队列是一种遵循先进先出 (FIFO / First In First Out) 原则的一组有序的项;队列在尾部添加新元素,并从头部移除元素。
class Queue {
constructor(items) {
this.items = items || []
}
enqueue(element){
this.items.push(element)
}
dequeue(){
return this.items.shift()
}
front(){
return this.items[0]
}
clear(){
this.items = []
}
get size(){
return this.items.length
}
get isEmpty(){
return !this.items.length
}
print() {
console.log(this.items.toString())
}
}
单项链表
// 链表节点
class Node {
constructor(ele) {
this.element = ele
this.next = null
}
}
// 链表
class LinkedList {
constructor() {
this.head = null //
this.length = 0 //长度
}
// 最后追加元素
append(element) {
//1. 创建新节点
const node = new Node(element)
//2.判断添加的是否第一个节点
if (this.head === null) { //this.length == 0 2.1 是第一个节点
this.head = node
} else { //2.2 不是第一个节点,找最后一个节点
var current = this.head
while(current.next) {
current = current.next
}
current.next = node //2.2.1最后一个节点指向新节点
}
//3. length + 1
this.length++
}
// 任意位置插入元素
insert(position, element) { //1.位置边界判断 0-length
if (position >= 0 && position <= this.length) {
const node = new Node(element)//创建新节点
let current = this.head //当前节点
let previous = null//先前节点
let index = 0//当前位置
if (position === 0) { //2.1位置是第一个
this.head = node
} else { //2.2位置不是第一个
while (index++ < position) { //2.2.1找到当前位置,右移节点
previous = current //当前节点→前节点
current = current.next //下一节点→当前节点
}
node.next = current //新节点.next = 当前节点
previous.next = node //前节点.next = 新节点
}//3. 长度加一
this.length++
return true
}
return false
}
// 移除指定位置元素
removeAt(position) { // 1.检查越界值 0-length-1
if (position > -1 && position < this.length) { //null不能删除
let current = this.head //当前节点,current.next下一个节点
let previous = null //前一个节点
let index = 0 //当前位置
if (position === 0) { //2.1删除位置为0
this.head = current.next //head指向 下一个节点
} else { //2.2删除位置不为0
while (index++ < position) { //2.2.1找到当前位置,右移节点
previous = current //当前节点→前节点
current = current.next //下一节点→当前节点
}
previous.next = current.next //前节点.next = 当前节点.next
}
this.length-- //3.长度--
return current.element //返回长度
}
return null
}
// 删除指定元素
remove(element) {
const index = this.findIndex(element)
return this.removeAt(index)
}
//修改指定位置元素
update(position,newEle){
if (position < -1 || position >= this.length) return false
let index= 0
let current = this.head
while(index++<position){ //2.查找正确节点
current = current.next //右移
}
current.element = newEle //3.修改节点
return true
}
//获取相应位置元素
get(position){
if (position < -1 || position >= this.length) return false
let index= 0
let current = this.head
while(index++<position){
current = current.next //右移
}
return current.element
}
// 寻找元素下标
findIndex(element) {
let current = this.head
let index = 0
while (current) {//开始查找
if (element === current.element) {
return index
}
index++
current = current.next //右移
}
return -1
}
// 转为字符串
toString() {
let current = this.head
let string = ''
while (current) {
string += ` ${current.element}` //凭借当前节点
current = current.next //节点右移
}
return string
}
isEmpty() {
return !this.length
}
size() {
return this.length
}
}
反转链表
1>2>3>4>5 反转为
1.取新的头结点reverseHead
2.遍历原链表,去除链表节点将其放到reverseHead新链表最前端
3. this.head = reverseHead.head;
//反转链表,返回新链表
reverseHead (){
if(this.length <=1 ){ //空节点,一个节点
return curr;
}
var reverseHead = new LinkedList(); //1.新头结点
let curr = this.head; //原链表结点1
let next = null; //原链表结点2
//2.遍历原链表,去除链表节点将其放到reverseHead新链表最前端
while(curr){
next = curr.next; //暂时保存下一个节点
curr.next = reverseHead.head; //下一个节点 连接 保存到前端
reverseHead.head = curr;
curr = next; //curr后移
}
3. this.head = reverseHead.head;
this.head = reverseHead.head;
reverseHead.length = this.length;
return reverseHead ;
}
双项链表
// 双向链表节点
class Node {
constructor(element) {
this.element = element
this.prev = null
this.next = null
}
}
// 双向链表
class DoublyLinkedList {
constructor() {
this.head = null
this.tail = null
this.length = 0
}
// 任意位置插入元素
insert(position, element) {
if (position >= 0 && position <= this.length){ //1.越界判断
const node = new Node(element)
let current = this.head //当前位
let previous = null //先前位
let index = 0
if (!head){ //当前长度为0 this.length==0 //2.为空
this.head = node
this.tail = node
} else { //当前长度不为0 //3.不为空
if (position === 0) { // 3.1 首位插入
current.prev = node //nextNode.prev
node.next = current //node.next
this.head = node // → node
}
} else if (position === this.length) {// 3.2 末位
current = this.tail //找到当前最后位
current.next = node //当前位.next = node
node.prev = current //node.prev = 当前位
this.tail = node //最后位更新
} else { // 3.3中位
while (index++ < position) {//3.3.1找到对应位置
previous = current //先前位右移
current = current.next //当前位右移
}
node.next = current //node.next
previous.next = node
current.prev = node
node.prev = previous //node.prev
}
this.length++
return true
}
}
return false
}
// 末位插入元素 追加元素
append(element){
let current = this.head
let previous = null
if(this.length == 0){ //1.元素为空
this.head = node
this.tail = node
}else{ //2.元素不为空
while(current.next){//2.1右移到末尾
current = current.next
}
current.next = node //当前位.next = node
node.prev = current //node.prev = 当前位
this.tail = node //最后位更新
}
}
// 移除指定位置元素 ---无指向的节点会回收
removeAt(position) {
if (position > -1 && position < this.length) { //1.越界判断
let current = this.head
let previous = null
let index = 0
// 2.首位移除
if (position === 0) {
this.head = this.head.next //→ node 消失
this.head.prev = null // node ← 消失
if (this.length === 1) { //只有一个节点,tial → null
this.tail = null
}
// 3.末位
} else if (position === this.length - 1) {
this.tail = this.tail.prev // node ← tail消失,tial指向prev
this.tail.next = null //钱洁典 = null
// 4.中位
} else {
while (index++ < position) { //右移找到节点
previous = current
current = current.next
}
previous.next = current.next //→ node 消失,prev = next
current.next.prev = previous // node ←消失, 指向prev
}
this.length--
return current.element
} else {
return null
}
}
// 转为字符串(正向)
toString(){
let str = ''
let current = this.head
while(current){
str += current.element + " "
current = current.next
}
retyrn str
}
// 转为字符串(逆向)
toForwardString(){
let str = ''
let current = this.tail
while(current){
str += current.element + " "
current = current.prev
}
retyrn str
}
}
二叉搜索树
二叉搜索树(BST)是二叉树的一种,但是它只允许你在左侧节点存储(比父节点)小的值, 在右侧节点存储(比父节点)大(或者等于)的值。
class Node { //树节点
constructor(key) {
this.key = key
this.left = null
this.right = null
}
}
class BinarySearchTree {
constructor() { //根节点
this.root = null
}
insert(key) {
const newNode = new Node(key)
const insertNode = (node, newNode) => {
if (newNode.key < node.key) { //1.1小于 & left为空
if (node.left === null) {
node.left = newNode
} else { //1.2left不为空,在left递归
insertNode(node.left, newNode)
}
} else { //2.1大于 & rigth为空
if (node.right === null) {
node.right = newNode
} else { //2.2rigth不为空,在rigth递归
insertNode(node.right, newNode)
}
}
}
if (!this.root) { //3.1根节点为空
this.root = newNode
} else { //3.2根节点不为空
insertNode(this.root, newNode)
}
}
//查找key,返回boolean
search(key){
let node = this.root; //0.node为根节点开始
while(node){// 1.node 不为空一直遍历
if(node.key < key){ //2.1大于右移
node = node.right;
}else if(node.key > key){//2.2小于左移
node = node.left;
}else{
return true;
}
}
return false;
}
//查找最值
remove(key){}
}