冒泡排序
- 对未排序的各元素从头到尾依次比较相邻的两个元素大小关系
- 如果左边的队员高, 则两队员交换位置
- 向右移动一个位置, 比较下面两个队员
- 当走到最右端时, 最高的队员一定被放在了最右边
- 按照这个思路, 从最左端重新开始, 这次走到倒数第二个位置的队员即可.
- 依次类推, 就可以将数据排序完成
function bubbleSort(arr){
var len = arr.length;
for(let i = length-1; i>=0; i--){
for(let j = 0; j < i; j++){
if(arr[j]>arr[j+1]){
[arr[j],arr[j+1]] = [arr[j+1],arr[j]];
}
}
}
return arr;
}
选择排序
- 选定第一个索引位置,然后和后面元素依次比较
- 如果后面的队员, 小于第一个索引位置的队员, 则交换位置
- 经过一轮的比较后, 可以确定第一个位置是最小的,一共进行
n
轮(数组长度) - 然后使用同样的方法把剩下的元素逐个比较即可
- 可以看出选择排序,第一轮会选出最小值,第二轮会选出第二小的值,直到最后
function selectionSort(arr){
var len = arr.length;
for(let i = 0; i<len; i++){ //n趟操作
let minIndex = i;
for(let j = i+1; j<len; j++){
if(arr[j]<arr[minIndex]){
minIndex = j;
}
}
[arr[minIndex],arr[i]] = [arr[i],arr[minIndex]];
}
return arr;
}
插入排序
- 从第一个元素开始,该元素可以认为已经被排序
- 取出下一个元素
temp
,在已经排序的元素序列中从后向前扫描 - 如果已排序的元素大于新元素
temp
,将已排序的元素移到下一位置 - 重复上一个步骤,直到找到已排序的元素小于或者等于新元素
temp
的位置 - 将新元素插入到已排序的元素后, 重复上面的步骤
function insertSort(arr){
var len = arr.length;
for(let i = 1; i<len; i++){
var temp = arr[i];
var j = i;
while(j > 0 && arr[j-1] > temp){
arr[j] = arr[j-1];
j--;
}
[arr[j],temp] = [temp,arr[j]];
}
return arr;
}
快速排序
- 对于序列
A[1]、A[2]、...、A[n]
,调整序列中元素的位置,使得A[1]
的左侧所有元素都不超过A[1]
,右侧所有的元素都大于A[1]
。 - 一次排序结束后对左右两边元素递归。
function Partition(arr, left, right){
var temp = arr[left];
while(left<right){
while(left < right && arr[right] > temp){
right--;
}
arr[left] = arr[right];
while(left < right && arr[left] < temp){
left++;
}
arr[right] = arr[left];
}
arr[left] = temp;
return left;
}
function quickSort(arr,left,right){
if(left<right){
var pos = Partition(arr,left,right);
quickSort(arr,left,pos-1);
quickSort(arr,pos+1,right);
return arr;
}
}
归并排序
步骤:
- 申请空间,使其大小为两个已排序序列之和,该空间用来存放合并后的序列
- 设定两个指针,初始分别为两个已排序序列的起始位置
- 比较两个指针指向的元素,选择相对较小的元素加入合并空间,并移动对应的指针到下一位置
- 重复步骤 3 直到某一个指针到达序列末尾
- 将另一序列剩下的所有元素直接复制到合并序列尾部
function mergeSort(arr){
var len = arr.length;
if(len < 2) return arr;
var middle = Math.floor(len / 2),
left = arr.slice(0, middle),
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;
}
堆排序
堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆(大根堆);或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。
基本思路:
- 将待排序序列构建成一个大顶堆,此时整个序列的最大值就是堆顶的根节点
- 将堆顶元素与末尾元素交换,将最大元素放到数组末端
- 重新调整结构,使其满足堆定义,然后继续交换堆顶元素和末尾元素,重复此步骤直到整个序列有序。
//生成大顶堆
function adjustHeap(arr, i, len){
//保存当前值
var temp = arr[i];
//从i节点的左子节点开始,即2i+1
for(let j = 2 * i + 1; j < len; j = 2 * j + 1){
//如果左子结点小于右子结点,j指向右子结点
if(j+1<len && arr[i] < arr[j+1]){
j++;
}
//如果子节点大于父节点,将子节点值赋给父节点(不用进行交换)值和索引都赋值
if(arr[j] > temp){
arr[i] = arr[j];
i = j;
} else {
break;
}
}
arr[i] = temp; //将temp值放到最终的位置
}
function heapSort(data) {
//构造大顶堆
//此时我们从最后一个非叶子结点开始,叶结点自然不用调整
//从第一个非叶子结点从下至上,从右至左调整结构
for (var i = data.length / 2 - 1; i >= 0; i--) {
adjustHeap(data, i, data.length);
}
// console.log(data);
//交换堆顶元素与末尾元素;不算最后一个元素,重新调整堆
for (var k = data.length - 1; k > 0; k--) {
//将堆顶元素与末尾元素进行交换
[data[0], data[k]] = [data[k], data[0]];
// console.log(data);
//不算最后一个元素,重新对堆进行调整
adjustHeap(data, 0, k);
}
return data;
}
栈
数组模拟栈
function Stack(){
var items = [];
this.push = (element) => {
return items.push(element);
};
this.pop = () => {
return items.pop();
};
//栈顶元素
this.peek = () => {
return items[items.length - 1];
}
this.isEmpty = () => {
return items.length == 0;
}
this.size = () => {
return items.length;
};
}
进制转换
// 十进制转二进制
function trans(number) {
var stack = new Stack();
var remainder;
while(number > 0){
remainder = number % 2 ;
number = Math.floor(number / 2);
stack.push(remainder);
}
var binaryString = "";
while(!stack.isEmpty()){
binaryString += stack.pop();
}
return binaryString;
}
// 使用原生数组实现
function trans(number) {
var remainder;
var stack = [];
while(number > 0){
remainder = number % 2 ;
number = Math.floor(number / 2);
stack.push(remainder);
}
var binaryString = "";
while(stack.length > 0){
binaryString += stack.pop();
}
return binaryString;
}
队列
数组模拟队列
function Queue() {
var items = [];
// 队列操作的方法
// enter queue方法
this.enqueue = function (element) {
items.push(element);
};
// delete queue方法
this.dequeue = function () {
return items.shift();
};
// 查看前端的元素
this.front = function () {
return items[0];
};
// 查看队列是否为空
this.isEmpty = function () {
return items.length === 0;
};
// 查看队列中元素的个数
this.size = function () {
return items.length;
};
}
优先级队列
- 插入一个元素的时候会考虑该数据的优先级(和其他数据优先级进行比较)。
- 比较完成后, 可以得出这个元素正确的队列中的位置。 其他处理方式和队列的处理方式一样。
- 要实现优先级队列, 最主要是要修改添加方法,还需要以某种方式来保存元素的优先级。
function PriorityQueue() {
var items = [];
// 封装一个新的构造函数, 用于保存元素和元素的优先级
function QueueElement(element, priority){
this.element = element;
this.priority = priority;
};
//添加元素的方法
this.enqueue = (element, priority)=>{
// 1.根据传入的元素, 创建新的QueueElement
var queueElement = new QueueElement(element, priority);
// 2.如果是空队列,直接放入
if (this.isEmpty()) {
items.push(queueElement);
return;
}
// 3.修改传入元素应该所处位置
if (queueElement.priority < items[0].priority) {
// 3.1:如果传入元素权重最高(数字最小),放在队列第一位
items.unshift(queueElement);
} else if (queueElement.priority > items[items.length -1].priority){
// 3.2:如果传入元素权重最低(数字最大),放在队列最后一位
items.push(queueElement);
} else {
// 3.3:传入的元素权重处于中间位置,找到合适的位置并插入
var start = 0;
var end = items.length - 1;
// 二分
while(start < end) {
var middle = Math.floor((start + end) / 2);
var current = items[middle].priority;
if(queueElement.priority < current){
end = middle;
} else if(queueElement.priority >= current){
start = middle;
}
}
items.splice(start, 0, queueElement);
}
};
// 删除元素的方法
this.dequeue = function () {
return items.shift();
};
// 获取前端的元素
this.front = function () {
return items[0];
};
// 查看元素是否为空
this.isEmpty = function () {
return items.length == 0;
};
// 获取元素的个数
this.size = function () {
return items.length;
};
}
// test
// 创建优先级队列对象
var pQueue = new PriorityQueue();
// 添加元素
pQueue.enqueue("abc", 10);
pQueue.enqueue("cba", 5);
pQueue.enqueue("nba", 12);
pQueue.enqueue("mba", 3);
// 遍历所有的元素
var size = pQueue.size();
for (var i = 0; i < size; i++) {
var item = pQueue.dequeue();
console.log(item.element + "----" + item.priority);
}
/*
mba----3
cba----5
abc----10
nba----12
*/
链表
//封装
function LinkedList() {
function Node(element){
this.element = element;
this.next = null;
}
this.length = 0;
this.head = null;
// 链表尾部追加元素方法
LinkedList.prototype.append = (element)=>{
// 1.根据新元素创建节点
var newNode = new Node(element);
// 2.判断原来链表是否为空
if(this.head === null){
this.head = newNode;
} else {
var current = this.head;
while (current.next) {
current = current.next;
}
//找到最后一项, 将其next赋值为newNode
current.next = newNode;
}
this.length++;
};
//链表元素转化为字符串
Linkedlist.prototype.toString = ()=>{
var current = this.head;
var listString = "";
while(current){
listString += "," + current.element;
current = current.next;
}
return listString.slice(1);
}
//根据下标插入元素
LinkedList.prototype.insert = (position, element) => {
if(position < 0 || position > this.length) return false;
// 2.定义变量, 保存信息
var newNode = new Node(element);
var current = this.head;
var previous = null;
index = 0;
// 3.判断是否列表是否在第一个位置插入
if(position == 0){
newNode.next = current;
this.head = newNode;
}else{
while(index++ < position){
previous = current;
current = current.next;
}
newNode.next = current;
previous.next = newNode;
}
this.length++;
return true;
};
//根据位置移除节点
LinkedList.prototype.removeAt = (position) =>{
// 1.检测越界问题: 越界移除失败, 返回null
if(position < 0 || position > this.length) return null;
// 2.定义变量
var current = this.head;
var previous = null;
var index = 0;
//3.判断是否是移除第一项
if(position == 0){
this.head = current.next;
}else{
while(index++ < position){
previous = current;
current = current.next;
}
previous.next = current.next;
}
this.length--;
// 4.返回移除的数据
return current.element;
};
// 根据元素获取链表中的位置
LinkedList.prototype.indexOf = function (element) {
// 1.定义变量, 保存信息
var current = this.head;
index = 0;
// 2.找到元素所在的位置
while (current) {
if (current.element === element) {
return index;
}
index++;
current = current.next;
}
// 3.来到这个位置, 说明没有找到, 则返回-1
return -1;
};
// 根据元素删除信息
LinkedList.prototype.remove = function (element) {
var index = this.indexOf(element);
return this.removeAt(index);
};
// 判断链表是否为空
LinkedList.prototype.isEmpty = function () {
return this.length == 0;
};
// 获取链表的长度
LinkedList.prototype.size = function () {
return this.length;
};
// 获取第一个节点
LinkedList.prototype.getFirst = function () {
return this.head.element;
};
}
树
定义
function TreeNode(x){
this.val = x;
this.left = null;
this.right = null;
}
前序遍历
递归
function preOrder(root) {
let res = [];
function __preOrder(root) {
if (!root) return null;
res.push(root.val);
__preOrder(root.left);
__preOrder(root.right);
}
__preOrder(root);
return res
}
非递归
function preOrder(root) {
if (!root) return null;
let nodes = [];
let res = [];
nodes.push(root);
while(nodes.length) {
let node = nodes.pop();
res.push(node.val);
node.right && nodes.push(node.right);
node.left && nodes.push(node.left);
}
return res
}
测试
1
/ \
2 3
/ \ / \
4 5 6 7
let root = {
val: 1,
left: {
val: 2,
left: {
val: 4,
left: null,
right: null
},
right: {
val: 5,
left: null,
right: null
}
},
right: {
val: 3,
left: {
val: 6,
left: null,
right: null
},
right: {
val: 7,
left: null,
right: null
}
}
}
console.log(preOrder(root)); // [1, 2, 4, 5, 3, 6, 7]
最长连续等于target的子序列
//滑动窗口
function solution(arr, target) {
let i = 0;
let j = 0;
let sum = arr[0];
while(i <= j && i < arr.length - 1){
if(sum === target){
return arr.slice(i, j + 1);
} else if(sum < target) {
sum += arr[++j];
} else {
sum -= arr[i++];
}
}
return false;
}
console.log(solution([3, 2, 1, 5, 4, 3, 7, 9], 12));
// 输出[2,1,5,4]