一.二叉树的遍历
二叉搜索树插入结点
function insertval(node,newnode){
if(newnode.val if(!node.left){ node.left=newnode; }else{ insertval(node.left,newnode); } } else{ if(!node.right){ node.right=newnode; }else{ insertval(node.right,newnode); } } } function inorder(node,callback){ if(!node){ inorder(node.left,callback); callback(node.value); inorder(node.right,callback); } } function preorder(node,callback){ if(node){ callback(node.value); preorder(node.left,callback); preorder(node.right,callback); } } function preorder(node,callback){ var stack=[]; if(node) stack.push(node); while(stack){ var temp=satck.pop(); callback(temp.value); if(temp.right) stack.push(temp.right); if(temp.left) stack.push(temp.left); } } function inorder(node,callback){ var arr=[]; while(true){ while(node){ arr.push(node); node=node.left; } if(!arr.length) break; var temp=arr.pop(); callback(temp.value()); node=temp.right; } } function postorder(node,callback){ if(node){ postorder(node.left,callback); postorder(node.right,callback); callback(node.value); } } function afterorder(node,callback){ var arr=[]; var res=[]; if(node) arr.push(node); while(arr.length){ var temp=arr.pop(); res.push(temp); if(temp.left) arr.push(temp.left); if(temp.right) arr.push(temp.right); } res.reverse(); res.forEach(item=>callback(item.value)); } function fromtoptobottom(root,callback){ var arr=[]; var data=[]; if(root){ arr.push(root); } while(arr.length){ var node=arr.shift(); if(node.left){ arr.push(node.left); } if(node.right){ arr.push(node.right); } data.push(node.val); } return data; } function minval(node){ if(node){ while(node&&node.left!==null){ node=node.left } return node.value; } return null } function maxvalue(node){ if(node){ while(node&&node.right){ node=node.right; } return node.value; } return null; } function selectval(node,text){ if(!node) return false; if(text return select(node.left,text); } else if(text>node.val){ return select(node.right,text); } else{ return true; } } function removenode(node,text){ if(!node) return null; if(text node.left=removenode(node.left,text); return node; } else if(text>node.val){ node.right=removenode(node.right,text); return node; } else{ //第一种情况删除一个叶节点 if(node.left===null&&node.right===null){ node=null; return node; } //第二种情况删除有一个子节点的结点 if(node.left===null){ node=node.right; return node; }else if(node.right===null){ node=node.left; return node; } //第三种情况删除有两个子节点的结点 var aux=minval(node.right); node.val=aux.val; node.right= removenode(node.right,aux.val); return node; } } 思想:相邻数据相比较,较大者放在后面,从前往后比较,共进行n-1轮。 function buble(arr){ for(var i=0;i for(var j=0;j if(arr[j]>arr[j+1]){ [arr[j],arr[j+1]]=[arr[j+1],arr[j]];//交换两者的值 } } } console.log(arr); } 思想:选出数组中最小值放在第一位,第二小放在第二位,以此类推。 function selectsort(A){ for(var i=0;i var min=i; for(var j=i+1;j if(arr[j] min=j; } } if(min!==i){ [arr[i],arr[min]]=[arr[min],arr[i]]; } } console.log(arr); } 输入:N个自然数序列 输出:满足a1<=a2<=…<=an的排序 计算时间是n*n 原地排序 对近乎有序的序列排序性能更好 function insertsort(A){ for(var i=1;i var key=A[i]; for(var j=i-1;j>=0 ;j--){ if(A[j]>key){ A[j+1]=A[j]; } else{ break; } } A[j+1]=key; } return A } 分治问题 要求解问题P: 分:将问题P分解为规模更小的子问题P1,P2,…,PK. 治:递归求解这些子问题。 合并:将子问题P1,P2,…,PK的解合并为问题P的解。 利用分治策略: 分:将n个元素分为两个n/2大小的子序列。 治:分别将两个子序列排序。 合并:将两个有序子序列合并,得到完整的有序序列。 输入:存放在数组A中的n个数 输出:输入n个数的有序序列 计算时间是nlogn 需要的存储空间是n 归并排序(自顶向下递归) function mergesort(A,p,r){ if(p var q=Math.floor((p+r)/2); mergesort(A,p,q); mergesort(A,q+1,r); merge(A,p,q,r) } } function merge(A,p,q,r){ var n1=q-p+1; var n2=r-q; var arr=[]; var arr1=[]; for(var i=0;i arr[i]=A[p+i]; } for(var j=0;j arr1[j]=A[q+1+j]; } arr[arr.length]=Infinity; arr1[arr1.length]=Infinity; var i=0; var j=0; for(var k=p;k<=r;k++){ if(arr[i]<=arr1[j]){ A[k]=arr[i]; i=i+1; } else{ A[k]=arr1[j]; j=j+1; } } console.log(A); } 归并排序(自底向上) function mergesortl(A){ for(var sz=1;sz<=A.length;sz+=sz){ for(var i=0;i+sz merge(A,i,i+sz-1,Math.min(i+sz+sz-1,A.length-1)) } } console.log(A); } 求逆序数: var xulie=0;//全局变量,用于统计逆序列数 mergesortxulie([2,4,3,1,4,12,6],0,6); function mergesortxulie(A,l,r){ if(l var p=Math.floor((l+r)/2); mergesortxulie(A,l,p); mergesortxulie(A,p+1,r); mergexulie(A,l,p,r); } console.log(A); } function mergexulie(A,p,q,r){ var temp=[]; var i=p; var j=q+1; var k=0; while(i<=q && j<=r){ if(A[i]<=A[j]){ temp[k++]=A[i++]; } else{ temp[k++]=A[j++]; xulie=xulie+(q-i+1); } } while(i<=q){ temp[k++]=A[i++]; } while(j<=r){ temp[k++]=A[j++]; } for(var i=0;i A[p+i]=temp[i]; } console.log(xulie); } 分治算法计算时间是nlogn 原地排序 分:将原数组围绕某划分元素X划分为两个子数组,使得前面子数组中元素<=X<=后面子数组中元素 治:递归对子数组进行排序 合并:不需要任何工作 关键:线性时间的划分过程 快排的最坏情况:输入数据是有序或者逆序的,基于最小或者最大元素进行划分,划分的一侧总是没有元素。 最好情况下划分的结果总是平均划分为对等的两侧 function quicksort(A,p,r){ if(p var q=partion(A,p,r) } if(p quicksort(A,p,q-1); } if(q+1 quicksort(A,q+1,r); } console.log(A); } function partion(A,p,r){ var x=A[r]; var i=p-1; for(var j=p;j if(A[j]<=x){ i=i+1; [A[i],A[j]]=[A[j],A[i]]; } } [A[i+1],A[r]]=[A[r],A[i+1]]; return i+1; } //快排实现寻找数组第几大元素 function quicksortfind(A,low,high,th){ var lows=low; var highs=high; var number=A[low]; while(low while(A[high]>=number&&low high--; } if(low A[low]=A[high]; } while(A[low]<=number&&low low++; } if(low A[high]=A[low]; } } A[low]=number; if(th==low){ return A[low]; } else if(th>low){ return quicksortfind(A,low+1,highs,th); } else{ return quicksortfind(A,lows,low-1,th); } } 计算时间为nlogn 原地排序 不稳定 MAX-HEAPIFY调整堆使其满足大顶堆的性质 BUILD-MAX-HEAP基于无序数组构建大顶堆 //堆排序 var len; function maxheap(A,i){ var l=A[2*i+1]; var r=A[2*i+2]; var largest=i; if(2*i+1 largest=2*i+1; } if(2*i+2 largest=2*i+2; } if(largest!=i){ [A[largest],A[i]]=[A[i],A[largest]]; maxheap(A,largest); } } function buildheap(A){ for(var i=Math.floor(len/2);i>=0;i--){ maxheap(A,i); console.log(A); } } function heapsort(A){ len=A.length; buildheap(A); for(var i=len;i>1;i--){ [A[0],A[i-1]]=[A[i-1],A[0]]; len--; maxheap(A,0); } console.log(A); } 计数排序:不做元素间的比较 输入:A[1…n],其中A[j]是{1,2,…,k} 输出;B[1..n],有序 辅助存储空间:C[1..k] 计算时间是k+n 是稳定的排序方法 //计数排序 function countsort(A,k){ varc=[]; for(vari=0;i<=k;i++){ c[i]=0; console.log(c); } for(varj=0;j varq=A[j]; c[q]=c[q]+1; console.log(c); } for(vari=1;i<=k;i++){ c[i]+=c[i-1]; console.log(c); } varB=[]; for(varm=A.length-1;m>=0;m--){ varr=A[m]; vard=c[r]; B[d-1]=r; c[r]=c[r]-1; } console.log(B); returnB; } 一位一位地排序 正确思想:首先按照最低位排序,并且需使用稳定的辅助排序算法。 假设所有输入由一个随机过程产生,且输入元素在[0,1)上均匀分布。 (1)为每个关键字值分配一个桶 即将A[i]插入到B[A[i]]中 (2)利用插入排序算法将B[i]排序 (3)将B[0],B[1],…,B[n-1]中的元素按顺序拼接在一起。 排序算法 最坏情况 最好情况 平均 应用场合 原地排序 稳定性 插入排序 n*n n n*n n<50时 原地排序 稳定 冒泡排序 n*n n n*n n<50时 原地排序 稳定 归并排序 nlogn nlogn nlogn 需要辅助存储空间,适用于外部排序 不是原地排序 稳定 堆排序 nlogn nlogn nlogn 适用于实时应用 原地排序 不稳定 快排 n*n nlogn nlogn 实用的通用排序算法 原地排序 不稳定 计数排序 k+n k+n k+n 固定小区间内的输入,需要辅助存储空间 不是原地排序 稳定 基数排序 d(k+n) d(k+n) d(k+n) 固定范围内的输入,需要辅助存储空间 不是原地排序 稳定 桶排序 n n n 均匀分布 不是原地排序 稳定中序遍历
先序遍历(递归)
先序遍历(非递归)
中序遍历(非递归)
后序遍历
后序遍历(非递归)
层序遍历
寻找搜索树最小值
寻找搜索树最大值
寻找搜索树特定值
搜索树移除一个节点
二.排序
1.冒泡排序
2.选择排序
3. 插入排序:
4.希尔排序
5.归并排序(求逆对数)
6.快排(求数组中第n大的元素)
7.堆排序
8.基于堆实现的优先级队列
9.线性时间排序
10.基数排序
11.桶排序
12.排序算法小结