例题—js(5)

本文介绍了JavaScript中的数据结构,包括列表、栈、队列、链表、字典、散列、图和二叉查找树,以及排序和查找算法。此外,还探讨了JavaScript的垃圾回收机制和选择器的使用。
摘要由CSDN通过智能技术生成

二十二、.统计字符串中出现最多的字符

function countStr(str){
    var obj={};
    var count=0;
    for(var i=0;i<str.length;i++){
        count=str.charAt(i);
        if(obj[count]){//将当前字符作为obj的属性
            obj[count]++;//如果出现一次就++
        }else{
            obj[count]=1;//没出现过赋值为1
        }
    }
    console.log(obj);
    var [n,m]=[0,0];
    for(var k in obj){
        if(obj[k]>n){
            n=obj[k];//出现最多次数的次数
            m=k;//出现次数最多的字符
        }
    }
    return `出现次数最多的字符是${m},出现次数为${n}`;
}
console.log(countStr('哈哈呵呵呵嘿嘿嘿嘿'));//出现次数最多的字符是嘿,出现次数为4次

二十三、js数据结构

数据结构:列表、栈、队列、链表、字典、散列、图和二叉查找树
排序算法:冒牌排序、选择排序、插入排序、希尔排序、归并排序和快速排序
查找算法:顺序查找和二分查找

列表
在日常生活中,人们经常使用列表:待办事项列表、购物清单、最佳十名榜单等等。而计算机程序也在使用列表,在下面的条件下,选择列表作为数据结构就显得尤为有用:

  1. 数据结构较为简单
  2. 不需要在一个长序列中查找元素,或者对其进行排序

反之,如果数据结构非常复杂,列表的作用就没有那么大了。


栈是一种特殊的列表,栈内的元素只能通过列表的一端访问,这一端称为栈顶。想象一下,我们平常在饭馆见到的一摞盘子就是现实世界常见的栈的例子,只能从最上面取盘子,盘子洗干净后,也只能放在最上面。栈被称为一种后入先出的数据结构。是一种高效的数据结构,因为数据只能在栈顶添加或删除,所以这样的操作很快。
使用条件:

只要数据的保存满足后入先出或先进后出的原理,都优先考虑使用栈

队列
队列也是一种列表,不同的是队列只能在队尾插入元素,在队首删除元素。想象一下,我们在银行排队,排在最前面的人第一个办理业务,而后面来的人只能排在队伍的后面,直到轮到他们为止。
使用条件:

只要数据的保存满足先进先出、后入后出的原理,都优先考虑使用队列
常见应用场景:

队列主要用在和时间有关的地方,特别是操作系统中,队列是实现多任务的重要机制
消息机制可以通过队列来实现,进程调度也是使用队列来实现

链表
链表也是一种列表,为什么需要出现链表,JavaScript中数组的主要问题时,它们被实现成了对象,与其他语言(比如C++和Java)的数组相对,效率很低。如果你发现数组在实际使用时很慢,就可以考虑使用链表来代替它。
使用条件:

链表几乎可以用在任何可以使用一维数组的情况中。如果需要随机访问,数组仍然是更好的选择。

字典
字典是一种以键-值对行驶存储数据的数据结构,JavaScript中的Object类就是以字典的形式设计的。JavaScript可以通过实现字典类,让这种字典类型的对象使用起来更加简单,字典可以实现对象拥有的常见功能,并相应拓展自己想要的功能,而对象在JavaScript编写中随处可见,所以字典的作用也异常明显了。

散列
散列(也称为哈希表)是一种的常用的数组存储技术,散列后的数组可以快速地插入或取用。散列使用的数据结构叫做散列表。在散列表上插入、删除和取用数据都非常快,但对于查找操作来说却效率低下,比如查找一组数组中的最大值和最小值。这些操作需要求助于其他数据结构,比如下面介绍的二叉查找树。

散列表在JavaScript中可以基础数组去进行设计。数组的长度是预先设定的,所有元素根据和该元素对应的键,保存在数组的特定位置,这里的键和对象的键是类型的概念。使用散列表存储数组时,通过一个散列函数将键映射为一个数字,这个数字的范围是0到散列表的长度。

即使使用一个高效的散列函数,依然存在将两个键映射为同一个值得可能,这种现象叫做碰撞。常见碰撞的处理方法有:开链法和线性探测法(具体概念有兴趣的可以网上自信了解)

使用条件:

可以用于数据的插入、删除和取用,不适用于查找数据


图由边的集合及顶点的集合组成。地图是我们身边很常见的现实场景,比如每两个城镇都由某种道路相连。上面的每个城镇可以看作一个顶点,连接城镇的道路便是边。边由顶点对(v1, v2)定义,v1和v2分别是图中的两个顶点。顶点也有权重,也成为成本。如果一个图的顶点对是有序的,则称之为有向图(例如常见的流程图),反之,称之为无序图。
使用场景(用图对现实中的系统建模):

交通系统,可以用顶点表示街道的十字路口,边可以表示街道。加权的边可以表示限速或者车道的数量。可以用该系统判断最佳路线及最有可能堵车的街道。
任何运输系统都可以用图来建模。比如,航空公司可以用图来为其飞行系统建模。将每个机场看成顶点,将经过两个顶点的每条航线看作一条边。加权的边可以表示从一个机场到另一个机场的航班成本,或两个机场间的距离,这取决于建模的对象是什么。
搜索图的算法主要有两种: 深度优先搜索和广度优先搜索。

二叉树和二叉查找树
树是计算机科学中经常用到的一种数据结构。树是一种非线性的数据结构,以分层的方式存储数据。
二叉树每个节点的子节点不允许超过两个。一个父节点的两个子节点分别称为左节点和右节点,通过将子节点的个数限定为2,可以写出高效的程序在树中插入、查找和删除数据。
二叉查找树(BST)是一种特殊的二叉树,相对较小的值保存在左节点中,较大的值保存在右节点中。这一特性使得查找的效率很高,对于数值型和非数值型的数据,比如单词和字符串,都是如此。
遍历BST的方式有三种:中序遍历(以升序访问树中所有节点,先访问左节点,再访问根节点,最后访问右节点)、先序遍历(先访问根节点,再以同样的方式访问左节点和右节点)、后序遍历(先访问叶子节点,从左子树到右子树,再到根节点)


排序算法
基本排序算法
基本排序算法,其核心思想是指对一组数组按照一定的顺序重新排列。重新排列时用到的技术是一组嵌套的for循环。其中外循环会遍历数组的每一项,内循环则用于比较元素。

冒泡排序
冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

function bubbleSort (arr) {
	var i = arr.length;
	while (i > 0) {
		var pos = 0
		for (var j = 0; j < i; j++) {
			if (arr[j] > arr[j+1]){
				pos = j
				var temp = arr[j]
				arr[j] = arr[j+1]
				arr[j+1] = temp
			}
		}
		i = pos
	}
	return arr
}
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(bubbleSort(arr));//[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]

选择排序
选择排序(Selection-sort)是一种简单直观的排序算法。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

function selectionSort (arr) {
	var len = arr.length;
	var minIndex, temp;
	for (var i = 0; i < len-1; i++) {
		minIndex = i;
		for (var j = i+1; j < len; j++) {
			if (arr[j] < arr[minIndex]) {
				minIndex = j
			}
		}
		temp = arr[minIndex]
		arr[minIndex] = arr[i]
		arr[i] = temp
	}
	return arr
}
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(selectionSort(arr));//[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]

插入排序
插入排序(Insertion-Sort)的算法描述是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间

function insertSort (arr) {
	var len = arr.length
	for (i = 1; i < len; i++) {
		var key = arr[i]
		var j = i - 1
		while (j >= 0 && arr[j] > key) {
			arr[j+1] = arr[j]
			j--;
		}
		arr[j+1] = key
	}
	return arr
}
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(insertSort(arr));//[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]

高级排序算法
高级数据排序算法,通常用于处理大型数据集的最高效排序算法,它们处理的数据集可以达到上百万个元素,而不仅仅是几百个或者几千个,下面我们将介绍希尔排序、归并排序和快速排序。

希尔排序
1959年Shell发明,第一个突破O(n^2)的排序算法;是简单插入排序的改进版;它与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增量排序。
希尔排序的核心在于间隔序列的设定。既可以提前设定好间隔序列,也可以动态的定义间隔序列。

function shellSort (arr) {
	var len = arr.length;
	var temp, gap = 1;
	while (gap < len /3 ) {
		gap = gap * 3 + 1
	}
	while (gap >= 1) {
		for (var i = gap; i < len; i++) {
			temp = arr[i]
			for (var j = i - gap; j >= 0 && arr[j] > temp; j-=gap) {
				arr[j+gap] = arr[j]
			}
			arr[j+gap] = temp
		}
		gap = (gap - 1) / 3
	}
	return arr
}
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(shellSort(arr));//[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]

归并排序
归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。归并排序是一种稳定的排序方法。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。

function mergeSort (arr) {
	var len = arr.length
	if (len < 2) {
		return arr
	}
	var middle = Math.floor(len / 2)
	var left = arr.slice(0, middle)
	var 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
}
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(mergeSort(arr));

快速排序
快速排序是处理 大数据集最快的排序算法之一。它是一种分而治之的算法,通过递归的方法将数据依次分解为包含较小元素和较大元素的不同子序列。该算法不断重复这个步骤知道所有数据都是有序的。
这个算法首先要在列表中选择一个元素作为基准值。数据排序围绕基准值进行,将列表中小于基准值的元素移到数组的底部,将大于基准值的元素移到数组的顶部。

function qSort (arr) {
	if (arr.length == 0) {
		return []
	}
	var left = []
	var right = []
	var pivot = arr[0]
	for (var i = 1; i < arr.length; i++) {
		if (arr[i] < pivot) {
			left.push(arr[i])
		} else {
			right.push(arr[i])
		}
	}
	return qSort(left).concat(pivot, qSort(right))
}
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(qSort(arr));

检索算法
在列表中查找数据有两种方式:顺序查找和二分查找。顺序查找适用于元素随机排列的列表;二分查找适用于元素已排序的列表。二分查找效率更高,但是必须在进行查找之前花费额外的时间将列表中的元素排序。

顺序查找
对于查找数据,最简单的方法就是从列表的第一个元素开始对列表元素逐个进行判断,直到找到了想要的结果,或者直到列表结尾也没有找到。这种方法称为顺序查找,有时也被称为线性查找。

function seqSearch (arr, data) {
  for (var i = 0; i < arr.length; i++) {
    if (arr[i] == data) {
      return i;
    }
  }
  return -1;
}
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(seqSearch(arr, 15))

二分查找
二分法查找,也称折半查找,是一种在有序数组中查找特定元素的搜索算法。查找过程可以分为以下步骤:

首先,从有序数组的中间的元素开始搜索,如果该元素正好是目标元素(即要查找的元素),则搜索过程结束,否则进行下一步。
如果目标元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半区域查找,然后重复第一步的操作。
如果某一步数组为空,则表示找不到目标元素。

function binSearch (arr, data) {
	var low = 0;
	var high = arr.length - 1
	while (low <= high) {
		var middle = Math.floor((low + high) / 2)
		if (arr[middle] < data) {
			low = middle + 1
		} else if (arr[middle] > data) {
			high = middle - 1
		} else {
			return middle
		}
	}
	return -1
}
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(binSearch(arr, 15))

二十四、js垃圾回收机制

自动垃圾回收机制就是找出那些不再继续使用的值,然后释放其占用的内存空间。垃圾回收器每隔固定的时间段就执行一次释放操作。
js最常用的是通过标记清除的算法来找到哪些对象是不再继续使用的
在局部作用域中,当函数执行完毕的时候,局部变量也就没有存在的必要了,因此垃圾回收器很容易做出判断并回收。
但是全局变量什么时候需要自动释放内存空间则很难判断,因此在开发中,需要尽量避免使用全局变量。
js的内存管理是自动执行的,是不可见的

变量的生命周期
当一个变量的生命周期结束之后它所指向的内存就应该被释放。JS有两种变量,全局变量和在函数中产生的局部变量。局部变量的生命周期在函数执行过后就结束了,此时便可将它引用的内存释放(即垃圾回收),但全局变量生命周期会持续到浏览器关闭页面。

var a=20;//在内存中给数值变量分配空间
alert(a+100);//使用内存
a=null;//使用完毕后,释放内存空间

检测垃圾的方法
(1)标记清除法
不能释放“进入环境”的变量所占的内存,只要执行流进入相应的环境,就有可能用到他们。而当变量离开环境的时候,则将其标记为“离开环境”。
进行标记的方式有很多种:翻转某个特殊位来来记录一个变量何时进入环境;使用一个“进入环境”变量列表和一个“离开环境”列表;
垃圾回收器在运行的时候会给所有变量都加上标记,然后,环境中的变量以及环境中的变量引用的变量,他们身上的标记会被去掉。
而在此之后再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。
最后,垃圾收集器完成内存清除工作,销毁那些带标记的值并回收它们所占用的内存空间。

function test(){ 
 var a = 10 ; //被标记 ,进入环境 
 var b = 20 ; //被标记 ,进入环境 
} 

test(); //执行完毕 之后 a、b又被标离开环境,被回收。

2)引用计数法(跟踪记录每个值被引用的次数。)
当声明了一个变量,并将一个引用类型值赋值给该变量时,则这个值的引用次数就是1。
如果同一个值又被赋给另外一个变量,则该值得引用次数加1。
相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数减 1。
当这个值的引用次数变成 0时,则说明没有办法再访问这个值了,因而就可以将其占用的内存空间回收回来。
这样,当垃圾收集器下次再运行时,它就会释放那 些引用次数为零的值所占用的内存。
但是很重要的一点是当遇到循环引用的时候,函数的引用次数就不会为0,所以不会被垃圾回收器回收内存,会造成内存泄露。在IE中涉及COM对象,就会存在循环引用的问题。


function test(){ 
 	var a = {} ; //a的引用次数为0 
 	var b = a ; //a的引用次数加1,为1 
 	var c =a; //a的引用次数再加1,为2 
 	var b ={}; //a的引用次数减1,为1  
}

二十五、辗转相除法
辗转相除法, 又名欧几里德算法(Euclidean algorithm),是求最大公约数的一种方法。它的具体做法是:用较小数除较大数,再用出现的余数(第一余数)去除除数,再用出现的余数(第二余数)去除第一余数,如此反复,直到最后余数是0为止。如果是求两个数的最大公约数,那么最后的除数就是这两个数的最大公约数。

function add(m,n){
   let r=0;//每轮的余数
   while(m%n!=0){//当余数不为0时进行下一轮
       r=m%n;//取余数
       m=n;//下一轮的被除数
       n=r;//下一轮的除数(本轮的余数)
   }
   return n;//当余数为0时返回
}
console.log(add(1997,615));

二十六、js的选择器

1.原生JS选择器
JS选择器常用的有getElementById()、getElementsByName()、getElementsByTagName()、getElementsByClassName()、querySelector()、querySelectorAll()

  • getElementById(ID):
    返回对指定ID的第一个对象的引用,如果在文档中查找一个特定的元素,最有效的方法是getElementById()
  • getElementsByName(name):
    返回文档中name属性为name值的元素,因为name属性值不是唯一的,所以查询到的结果有可能返回的是一个数组,而不是一个元素。
  • getElementsByTagName(tagname): 返回文档中指定标签的元素
  • getElementsByClassName():返回文档中所有指定类名的元素
  • querySelector():返回文档中匹配指定css选择器的第一个元素
  • querySelectorAll():返回文档中匹配指定css选择器的第一个元素

2.jQuery选择器
内容
基本选择器有ID选择器、类选择器、标签选择器、通用选择器,事件的添加方法如下:
$(…).事件名(function() { });
属性样式有:

  • $(…).css(“border”,“1px solid red”)
  • $(…).css({…})
  • $(…).css(“border”)
  • $(…).attr(属性名,值)
  • $(…).html() innerHTML
  • $(…).text() innerText
  • $(…).val() value值
  • $(…).addClass() 增加
  • $(…).removeClass() 移除
  • $(…).toggleClass() 开关**

3.jQuery选择器的详细使用方法
在这里插入图片描述


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值