0812
一、栈
① 先进后出(FILO),只能在一端入栈 和 出栈
② 栈的方法有:
------push()入栈 ,
------ pop()出栈 ,
------ peek()查看栈顶元素 ,
------ isEmpty() 判断是否为空 ,
------size() 栈的长度
③ 封装一个栈:
class Stack {
constructor() {
// 栈中的属性
this.items = []
}
// 栈相关的方法
// 压栈操作
push(element) {
this.items.push(element)
}
// 出栈操作
pop() {
return this.items.pop()
}
// peek操作
peek() {
return this.items[this.items.length - 1]
}
// 判断栈中的元素是否为空
isEmpty() {
return this.items.length == 0
}
// 获取栈中元素的个数
size() {
return this.items.length
}
}
二、队列
① 先进先出(FIFO), 固定在一端进队,另一端出队
② 队列的方法:
------enqueue()入队 ,
------dequeue 出队 ,
------front()查看队首元素 ,
------ isEmpty()判空 ,
------size()队列长度
③ 封装一个队列:
class Queue{
constructor(){
this.item = []
}
enqueue(ele){
this.item.push(ele)
}
dequeue(){
return this.item.shift()
}
front(){
return this.item[0]
}
isEmpty(){
return this.item.length == 0
}
size(){
return this.item.length
}
}
④ 优先级队列:
三、链表
1、单向链表
① 链表结构:
------head 指向链表头结点
------length 链表长度
② 链表中节点结构:
------data 存放数据
------next 存放下一节点 地址
③ 链表方法:
------append(ele) 创建新节点 ;
------ insert(position,ele) 插入新节点 ;
------ removeAt(position)移除指定的项 ;
------indexOf(ele)查找目标元素下标 ;
------ remove(ele)从列表中移除一项 ;
------toString() 转成字符串 ;
------isEmpty()判空 。
④ 封装一个链表:
// 节点结构
class Lnode {
constructor(data) {
this.data = data
this.next = null
}
}
class LinkList {
constructor() {
this.head = null
this.length = 0
}
// 在链表尾部 新增节点
append(data) {
let newNode = new Lnode(data)
// 链表为空时 直接将新节点设为 头结点
if (this.head == null) {
this.head = newNode
}
// 链表不为空时
else {
// 找到最后一个节点
let current = this.head
while (current.next !== null) {
current = current.next
}
// 让最后一个节点指向 新节点
current.next = newNode
}
this.length++
}
// 在指定位置 新增节点
insert(position, data) {
if (position < 0 || position > this.length || !Number.isInteger(position)) {
return false
}
let newNode = new Lnode(data)
if (position == 0) {//在首部添加新节点
newNode.next = this.head
this.head = newNode
this.length++
} else if (position == this.length) {
this.append(data)
} else {
let current = this.head, index = 0
while (index < position - 1) {
current = current.next
index++
}
newNode.next = current.next.next
current.next = newNode
this.length++
}
}
removeAt(position) {
if (position < 0 || position > this.length || !Number.isInteger(position)) {
return false
}
if (position == 0) {
this.head = this.head.next
} else {
let current = this.head, index = 0
while (index < position - 1) {
current = current.next
index++
}
current.next = current.next.next
}
this.length--
}
indexOf(data) {
let current = this.head, index = 0
// console.log(this.length);
while (index < this.length) {
if (current.data == data) {
return index
} else {
current = current.next
index++
}
}
return -1
}
remove(data) {
this.removeAt(this.indexOf(data))
}
isEmpty() {
return this.length == 0
}
toString() {
let current = this.head, index = 0, str = ""
while (index < this.length) {
str += "-" + current.data
current = current.next
index++
}
return str.slice(1)
}
}
2、双向链表
① 链表结构:
------head 指向 链表头结点 ;
------tail 指向链表 尾结点 ;
------length 链表长度 。
② 链表的节点结构:
------prev 存放上一节点 地址 ;
------next 存放下一节点 地址 ;
------data 存放数据 。
③ 链表方法:
------append(data)在链表尾部 新增新节点 ;
------insert(position ,data)在指定位置 新增新节点;
(在链表中间新增时 ,现将新节点连接上去 ,再连接 前后节点)
------removeAt (position) 删除指定位置元素
------indexOf(data) 查找data在链表中的 位置
------remove(data)删除data元素
------isEmpty()判空 ;
------forwardString() 正向转字符串
------reverseString() 逆向转字符串
④ 封装一个 双向链表:
class DoublyLnode {
constructor(data) {
this.data = data
this.prev = null
this.next = null
}
}
class DoublyLinkedList {
constructor() {
this.head = null
this.tail = null
this.length = 0
}
// 在链表尾部 新增一个节点
append(data) {
let newNode = new DoublyLnode(data)
if (this.length == 0) {
this.head = newNode
this.tail = newNode
} else {
this.tail.next = newNode
newNode.prev = this.tail
this.tail = newNode
}
this.length++
}
// 在指定位置 新增节点
insert(position, data) {
if (position < 0 || position > this.length || !Number.isInteger(position)) {
return false
}
let newNode = new DoublyLnode(data)
if (position == 0) {
this.head.prev = newNode
newNode.next = this.head
this.head = newNode
this.length++
} else if (position == this.length) {
this.append(data)
} else {
let current = this.head, index = 0;
while (index < position - 1) {
current = current.next
index++
}
newNode.next = current.next
newNode.prev = current
current.next.prev = newNode
current.next = newNode
this.length++
}
}
// 删除指定位置 元素
removeAt(position) {
if (position < 0 || position > this.length || !Number.isInteger(position)) {
return false
}
if (position == 0) {
this.head.next.prev = null
this.head = this.head.next
} else if (position == this.length - 1) {
this.tail.prev.next = null
this.tail = this.tail.prev
} else {
let current = this.head, index = 0;
while (index < position - 1) {
current = current.next
index++
}
current.next = current.next.next
current.next.prev = current
}
this.length--
}
indexOf(data) {
let current = this.head, index = 0
while (index < this.length) {
if (current.data == data) {
return index
} else {
current = current.next
index++
}
}
return -1
}
remove(data) {
this.removeAt(this.indexOf(data))
}
isEmpty() {
return this.length == 0
}
forwardString() {
let current = this.head, index = 0, str = ""
while (index < this.length) {
str += "-" + current.data
current = current.next
index++
}
return str.slice(1)
}
reverseString() {
let current = this.tail, index = this.length - 1, str = ""
while (index >= 0) {
str += "-" + current.data
current = current.prev
index--
}
return str.slice(1)
}
}
3、单向循环链表
① 链表结构 ,链表节点结构,方法同 单向链表
② 封装一个单向循环链表:
class CLnode {
constructor(data) {
this.data = data
this.next = null
}
}
class CycleLinkList {
constructor() {
this.head = null
this.length = 0
}
// 在链表尾部 新增节点
append(data) {
let newNode = new CLnode(data)
if (this.length == 0) {
this.head = newNode
newNode.next = this.head
} else {
let current = this.head
while (current.next != this.head) {
current = current.next
}
current.next = newNode
newNode.next = this.head
}
this.length++
}
// 在指定位置 新增节点
insert(position, data) {
if (position < 0 || position > this.length || !Number.isInteger(position)) return false;
let newNode = new CLnode(data)
if (position == 0) {
if (this.length == 0) {
this.head = newNode
newNode.next = this.head
} else {
let current = this.head
while (current.next != this.head) {
current = current.next
}
current.next = newNode
newNode.next = this.head
this.head = newNode
}
this.length++
} else if (position == this.length) {
this.append(data)
} else {
let current = this.head, index = 0
while (index < position - 1) {
current = current.next
index++
}
newNode.next = current.next
current.next = newNode
this.length++
}
}
// 删除指定位置 的元素
removeAt(position) {
if (position < 0 || position > this.length || !Number.isInteger(position) || this.length == 0) return false;
if (position == 0) {
if (this.length == 1) {
this.head = null
} else {
let current = this.head
while (current.next != this.head) {
current = current.next
}
this.head = this.head.next
current.next = this.head
}
} else {
let current = this.head, index = 0
// 将 current移动到 目标节点的前一个位置
while (index < position - 1) {
current = current.next
index++
}
current.next = current.next.next
// 当current为最后一个节点时 , current.next.next == this.head
}
this.length--
}
indexOf(data) {
let current = this.head, index = 0
while (index < this.length) {
if (current.data == data) {
return index
} else {
current = current.next
index++
}
}
return -1
}
remove(data) {
this.removeAt(this.indexOf(data))
}
isEmpty() {
return this.length == 0
}
toString() {
let current = this.head, index = 0, str = ""
while (index < this.length) {
str += "-" + current.data
current = current.next
index++
}
return str.slice(1)
}
}
4、双向循环链表
① 链表结构 ,链表节点结构,方法同 双向链表
② 封装一个双向循环链表:
class Cdnode {
constructor(data) {
this.prev = null
this.data = data
this.next = null
}
}
class CycleDlist {
constructor() {
this.head = null
this.tail = null
this.length = 0
}
append(data) {
// 新建一个节点
let newNode = new Cdnode(data)
// 标记
let current = this.head, index = 0
// 当为空链表时
if (this.length == 0) {
// 直接将head tail 指向newNode
this.head = newNode
this.tail = newNode
this.head.prev = this.tail
this.tail.next = this.head
} else {// 链表不为空时 在链表尾部 添加新结点
// 找到最后一个节点
while (index++ < this.length - 1) {
current = current.next
}
newNode.prev = current
newNode.next = this.head
current.next = newNode
this.head.prev = newNode
this.tail = newNode
}
this.length++
}
// 在指定位置 新增结点
insert(position, data) {
// 判断位置是否合法
if (position < 0 || position > this.length || !Number.isInteger(position)) return false
let current = this.head , index = 0
let newNode = new Cdnode(data)
if (position == 0) {//在首部新增结点
if (this.length == 0) {//链表为空时
this.head = newNode
this.tail = newNode
this.head.prev = this.tail
this.tail.next = this.head
} else { //链表不为空时
newNode.next = this.head
newNode.prev = this.tail
this.head.prev = newNode
this.tail.next = newNode
this.head = newNode
}
this.length++
}else if(position == this.length){//在链表尾部 新增结点
this.append(data)
}else{ //在链表中间新增结点
// 找到目标结点的上一个位置
while(index++ < position -1){
current = current.next
}
newNode.next = current.next
newNode.prev = current
current.next.prev = newNode
current.next = newNode
this.length++
}
}
// 移除指定位置 的结点
removeAt(position){
// 判断位置是否合法
if (position < 0 || position >= this.length || !Number.isInteger(position)||this.length == 0) return false
let current = this.head ,index = 0
if(position == 0){ //移除首部结点
if(this.length == 1){ // 只有一个结点时
this.head = null
this.tail = null
}else{//有多个结点
this.head.next.prev = this.tail
this.tail.next = this.head.next
this.head = this.head.next
}
}else if(position == this.length -1){ //移除尾部结点
// 找到尾部结点的前一个结点
while(index++ < position -1){
current = current.next
}
current.next = this.head
this.head.prev = current
this.tail = current
}else{//移除中间结点
// 找到目标结点 的前一个 结点
while(index++ < position -1){
current = current.next
}
current.next = current.next.next
current.next.prev = current
}
this.length--
}
indexOf(data){
let current = this.head ,index =0
for(let i=0; i<this.length; i++){
if(current.data == data){
return index
}else{
current = current.next
index++
}
}
return -1
}
remove(data){
this.removeAt(this.indexOf(data))
}
isEmpty() {
return this.length == 0
}
forwardString() {
let current = this.head, index = 0, str = ""
while (index < this.length) {
str += "-" + current.data
current = current.next
index++
}
return str.slice(1)
}
reverseString() {
let current = this.tail, index = this.length - 1, str = ""
while (index >= 0) {
str += "-" + current.data
current = current.prev
index--
}
return str.slice(1)
}
}
四 、 集合
① 实质是一个对象 Set(),不能有重复值
② 集合的方法:
add() 在集合中 添加新元素 ; has(data)集合中是否 包含目标元素 ;delete(ele) ; clear() ; values() ; size() ; union(set)并集 ; intersection(set) 交集 ;
difference(set) 差集; subset(set) 子集
class Set{
constructor(){
this.item = {}
}
has(ele){
return this.item.hasOwnProperty(ele)
}
add(ele){
if(!this.has(ele)){
this.item[ele] = ele
}
return !this.has(ele)
}
delete(ele){
return delete this.item[ele]
}
clear(){
this.item = {}
}
values(){
return Object.values(this.item)
}
size(){
return Object.values(this.item).length
}
// 并集
union(set){
let newset = new Set()
//将两个集合分别加在新数组中
this.values().forEach(ele=>{
newset.add(ele)
})
set.values().forEach(ele=>{
newset.add(ele)
})
return newset
}
// 交集
intersection(set){
let newset = new Set()
// 遍历this 集合 在set集合中也存在的加入 新数组
this.values().forEach(ele=>{
if(set.has(ele)){
newset.add(ele)
}
})
return newset
}
// 差集
difference(set){
let newset = new Set()
//在this 集合中存在 但在 set集合中不存在的加入 新数组
this.values().forEach(ele=>{
if(!set.has(ele)){
newset.add(ele)
}
})
return newset
}
// 子集
subset(set){
// 遍历 set集合 如果有元素 不存在于 this 集合
// 返回false 说明不是this 的子集
for(let i=0; i<set.values().length; i++){
if(!this.has(set.values()[i])){
return false
}
}
return true
}
}
五、字典
① 实质上是一个对象 , 有特殊方法和要求
② 封装一个 字典:
class Dictionay {
constructor() {
this.item = {}
}
// 新增元素
set(key, value) {
// 当对象含有该键值时 做赋值操作
this.item[key] = value
}
// 查找字典中 是否含有目标键值
has(key) {
return this.item.hasOwnProperty(key)
}
// 移除目标key
remove(key) {
return delete this.item[key]
}
get(key) {
return this.item[key]
}
clear() {
this.item = {}
}
size() {
return Object.values(this.item).length
}
keys() {
return Object.keys(this.item)
}
values() {
return Object.values(this.item)
}
}
六、树
① 定义:n个节点构成的有限集合
② 术语
---结点的度:结点子树的个数
---树的度:所有结点中 最大的结点度数
---叶子结点: 度为 0 的结点
---父节点,子节点 , 兄弟结点
---路径:结点A到结点B 途径的结点 ,路径所包含边的个数 为 路径长度
---结点的层次 : 根结点在 1层 , 任意结点的层次 是 其父结点层次+1
---树的深度: 等于 最大的结点层次
1、二叉树
① 每个结点 都只有两个子结点
② 特性:
第 i 层 最大结点数 = 2^(i-1);
深度为k的最大结点数 = 2^k - 1;
叶子结点数 = 度为2 的结点数 + 1
③ 完美二叉树
④ 完全二叉树
2、二叉搜索树
① 左子结点 的值永远小于 父节点; 右子结点 的值永远 大于 父节点
② 封装一个二叉搜索树:
3、排序