《学习javascript数据结构与算法》算法

排序算法
  • 冒泡排序:拿当前值跟后面的值挨个比较 如果当前值比后面的值大 就替换位置

  • 选择排序:每次找到数组中最小的值的索引 跟当前索引位置元素交换

  • 插入排序:把当前索引的值当作一个基准 拿前一个值跟这个值对比 如果比他大就替换他的位置 最后把它插入到自己该在的位置。排序小型数组时,此算法比选择排序和冒泡排序性能要好

  • 归并排序:把数组先剁两半 然后各自排序 不断递归这个过程 最后把两大半数组排序,其复杂度跟快排一样 为O(nlogn) logn的意思是以2为底n的对数 说白了就是2的几次方等于n

  • 快排:快排的复杂度和归并排序一样为O(nlogn) 一指针两拨片
    1.首先,从数组中选择中间一项作为主元。
    2.创建两个指针,左边一个指向数组第一个项,右边一个指向数组最后一个项。然后移动左右指针,左找大,右找小,交换位置
    重复这个过程,直到左指针超过了右指针。这个过程将使得比主元小的值都排在主元之
    前,而比主元大的值都排在主元之后。这一步叫作划分操作
    3.接着,算法对划分后的小数组(较主元小的值组成的子数组,以及较主元大的值组成的 子数组)重复之前的两个步骤,直至数组已完全排序
  • 二分搜索:
    (1) 选择数组的中间值。
    (2) 如果选中值是待搜索值,那么算法执行完毕(值找到了)。
    (3) 如果待搜索值比选中值要小,则返回步骤1并在选中值左边的子数组中寻找。 (4) 如果待搜索值比选中值要大,则返回步骤1并在选种值右边的子数组中寻找。
	function ArrayList(){
	  var array = [];
	  let times = 0
	  	this.insert = function(item){ 
	        array.push(item);
		};
	  	this.toString= function(){ 
	        return array.join();
		};
		//拿当前值跟后面的值挨个比较 如果当前值比后面的值大 就替换位置
		this.bubbleSort = function(){
	    	var length = array.length;
	    	for (var i=0; i<length; i++){
	    		for (var j=0; j<length-1; j++ ){ 
			    	if (array[j] > array[j+1]){
			        	swap(j, j+1);           
					} 
				}
			}
			return array;
		}

		var swap = function(index1, index2){
	    	var aux = array[index1];
	    	array[index1] = array[index2];
	    	array[index2] = aux;
		}

		this.modifiedBubbleSort = function(){
		    var length = array.length;
		    for(var i=0; i<length; i++){
		        for (var j=0; j<length-i; j++ ){
		            if(array[j] > array[j+1]){
		            	swap(j, j+1);
					}
				} 
			}
			return array
		};
		//选择排序:每次找到数组中最小的值的索引 跟当前索引位置元素交换
		this.selectionSort = function(){
	      	let length = array.length;
	      	for(let i=0;i<length;i++){
	      		let minIndex = i;
	      		for(let j = i;j<length;j++){
	      			if(array[minIndex]>array[j]){
	      				minIndex = j;
	      			}
	      		}
	      		if(minIndex!==i){
	      			swap(minIndex,i);
	      		}
      		}
      		return array;
		};
		//插入排序  思想 把当前索引的值当作一个基准  拿前一个值跟这个值对比 如果比他大就替换他的位置 最后把它插入到自己该在的位置 
		//排序小型数组时,此算法比选择排序和冒泡排序性能要好
		this.insertionSort = function(){
	    	let length = array.length,j,temp;
	    	for(let i=1;i<length;i++){
	    		let j = i;
	    		temp = array[i];
	    		// 拿前一个值跟当前值对比 如果比他大就替换他的位置
	    		while(j>0&&array[j-1]>temp){
	    			array[j] = array[j-1];
	    			j--;
	    		}
	    		// 把当前值插入到自己该在的位置
	    		array[j] = temp;  
	    	}
	    	return array;
		};

		this.mergeSort = function(){
    		return mergeSortRec(array);
		};
		// 归并排序。把数组先剁两半 然后各自排序 不断递归这个过程 最后把两大半数组排序
		// 其复杂度跟快排一样 为O(nlogn)   logn的意思是以2为底n的对数   说白了就是2的几次方等于n
		var mergeSortRec = function(array){
    		var length = array.length;
    		if(length === 1) {    
        		return array;      
    		}
    		var mid = Math.floor(length / 2),
       		left = array.slice(0, mid),
        	right = array.slice(mid, length);		
			return merge(mergeSortRec(left), mergeSortRec(right));
		};

		var merge = function( left, right){
			//[5] [3]        [3,5]
			//[2] [4]        [2,4]
			//[1] [2,4]    	 [1,2,4]
			//[3,5] [1,2,4]	 [1,2,3,4,5]
   			var result = [], 
				il = 0,
				ir = 0;
			while(il < left.length && ir < right.length) { 
				if(left[il] < right[ir]) { //il +1
    				result.push(left[il++]);  
				} else { //ir +1 +1 +1
					result.push(right[ir++]);
				}
			}
			while(il < left.length){
     			result.push(left[il++]);
			}
			while(ir < right.length){
    			result.push(right[ir++]);
			}
			return result;
		};

		// 快排的复杂度和归并排序一样为O(nlogn)    一指针两拨片
		// 1.首先,从数组中选择中间一项作为主元。
		// 2.创建两个指针,左边一个指向数组第一个项,右边一个指向数组最后一个项。然后移动左右指针,左找大,右找小,交换位置
		// 重复这个过程,直到左指针超过了右指针。这个过程将使得比主元小的值都排在主元之 
		// 前,而比主元大的值都排在主元之后。这一步叫作划分操作
		// 3.接着,算法对划分后的小数组(较主元小的值组成的子数组,以及较主元大的值组成的 子数组)重复之前的两个步骤,直至数组已完全排序
		this.quickSort = function(){
        	return quick(array,  0, array.length - 1);
		};

		var quick = function(array,left,right){
			//[5,3,1,2,4] 0 4 
	        var index; 
	        if(array.length > 1){ 
	            index = partition(array, left, right); 
	 		};
	    	if(left < index - 1) {
	        	quick(array,left,index-1);
			}
	    	if (index < right) { 
	        	quick(array, index, right);
			}  
			return array;
		}

		var partition = function(array, left, right) {
			// [5,3,1,2,4] 0 4
        	var pivot = array[Math.floor((right + left) / 2)],//1
        	i = left, //0
   			j = right; //4
   			while (i < j) {
   				// [1,3,5,2,4]
   				while(array[i] < pivot) {
					i++; 
				}
    			while(array[j] > pivot) { 
        			j--;
        		}
        		if(i <= j){ 
        			//j-2  i=0
        			swapQuickStort(array, i, j); 
					i++;
					j--;
				} 
			}
			return i;//1 
		};

		var swapQuickStort = function(array, index1, index2){
	        var aux = array[index1];
	        array[index1] = array[index2];
	        array[index2] = aux;
		};
		// 二分搜索
		this.binarySearch = function(item){
			this.quickSort();
			console.log(array)
			let start=0,end=array.length-1,mid,element;
			while(start<=end){
				mid = Math.floor((start+end)/2);
				element = array[mid];
				if(element<item){
					start = mid+1;
				}else if(element>item){
					end = mid-1;
				}else{
					return mid
				}
			}
			return -1; 
		}
	}

	let arr = new ArrayList();

	arr.insert(5);
	arr.insert(3);
	arr.insert(1);
	arr.insert(2);
	arr.insert(4);

	arr.insert(9);
	arr.insert(8);
	arr.insert(7);
	arr.insert(6);
	arr.insert(16);
	arr.insert(26);
	arr.insert(66);

	console.log(arr.binarySearch(66))

斐波那契数列

function fibonacci(num){
    if(num==1||num==2){
        return 1;	
    }
    return fibonacci(num-1)+fibonacci(num-2)
}

function fib(num){
    let n  = 1;
    let n1 = 1;
    let n2 = 1;
    for(let i = 3;i<num;i++){
        n = n1+n2;
        n1 = n2;
        n2 = n;
    }
    return n
}

动态规划
动态规划(Dynamic Programming,DP)是一种将复杂问题分解成更小的子问题来解决的优化技术。

要注意动态规划和分而治之(归并排序和快速排序算法中用到的那种)是不 同的方法。分而治之方法是把问题分解成相互独立的子问题,然后组合它们的答 案,而动态规划则是将问题分解成相互依赖的子问题

能用动态规划解决的一些著名的问题如下

背包问题:给出一组项目,各自有值和容量,目标是找出总值最大的项目的集合。这个 问题的限制是,总容量必须小于等于“背包”的容量

最长公共子序列:找出一组序列的最长公共子序列(可由另一序列删除元素但不改变余 下元素的顺序而得到)。

矩阵链相乘:给出一系列矩阵,目标是找到这些矩阵相乘的最高效办法(计算次数尽可 能少)。相乘操作不会进行,解决方案是找到这些矩阵各自相乘的顺序
硬币找零:给出面额为d1…dn的一定数量的硬币和要找零的钱数,找出有多少种找零的 方法。
图的全源最短路径:对所有顶点对(u, v),找出从顶点u到顶点v的最短路径

动态规划 解决最少硬币找零问题 把一个大问题归结到很多小问题 把小问题的结果缓存到cache对象中 当我们找36的结果时 会用36 挨个减去coins 中的值得到一个最优解 36 的话就是1 + cache中的35的结果 10 +25 所以36 的结果是[1, 10, 25]


function MinCoinChange(coins){
        var coins = coins; 
        var cache = {}; 
        this.makeChange = function(amount) {
            var me = this;
            if(!amount){ 
                return [];
            }
            if(cache[amount]){
                return cache[amount];
            }
            var min = [], newMin, newAmount;
            for(var i=0; i<coins.length; i++){
                var coin = coins[i];
                newAmount = amount - coin;
                if (newAmount >= 0){
                    newMin = me.makeChange(newAmount);
                }
               	// debugger;
                if (
                    newAmount >= 0 && 
                    (newMin.length < min.length-1 || !min.length)
                    && (newMin.length || !newAmount) 
                    ){
                    min = [coin].concat(newMin);
                    console.log(min,coin) 
				} 
			}
            return (cache[amount] = min); 
        };
        this.getCache = function(){
        	console.log(cache);
        }
	}
    var minCoinChange = new MinCoinChange([1, 5, 10, 25]);
	minCoinChange.makeChange(36);
	minCoinChange.getCache();

贪心算法解决最少硬币找零问题 把数组从小到大排序 然后从后往前累加得到结果
贪心算法所执行的效率比动态规划快。但是得到的结果却不是最优解
如果用[1, 3, 4]面额。
执行贪心算法,会得到结果[4, 1, 1]。
如果用动态规划的解法,会得到最优的结果[3, 3]。

function MinCoinChanges(coins){
    var coins = coins; 
    this.makeChange = function(amount) {
        var change = [],
            total = 0;
        for (var i=coins.length; i>=0; i--){ 
            var coin = coins[i];
            while (total + coin <= amount) {
                change.push(coin);
                total += coin;
            } 
        }
        return change;
    };
}
var minCoinChanges = new MinCoinChanges([1,3,4]);
console.log(minCoinChanges.makeChange(6));
发布了77 篇原创文章 · 获赞 7 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_37653449/article/details/88766057