数据结构学习笔记
栈学习:
//栈:后进先出,后面进入栈中的数据要先取出才能操作之前进入栈中的数据
function Static(){
this.items = [];
//1、push():添加一个新元素到栈顶的位置
Static.prototype.push = function(element){
return this.items.push(element)
}
//2、pop():移除栈顶的元素,同时返回被移除的元素
Static.prototype.pop = function(){
return this.items.pop()
}
//3、peek():返回栈顶的元素,不对栈进行任何的修改(仅仅是查看栈顶元素,并返回这个
Static.prototype.peek = function(){
return this.items[this.items.length - 1]
}
//4、isEmpty():如果栈里没有任何元素,就会返回true,否则返回false
Static.prototype.isEmpty = function(){
return this.items.length === 0
}
//5、size():返回栈里的元素个数,这个方法和数组里的length属性很类似
Static.prototype.size = function(){
return this.items.length
}
//6、toString():将栈结构的内容以字符串的形式返回
Static.prototype.toString = function(){
let resultString =''
for(let i=0;i<this.items.length;i++){
resultString += this.items[i]+''
}
return resultString;
}
}
//js栈的操作:十进制转二进制(dec:十进制,bin:二进制)
function DecToBin(decNumber){
//1.定义栈对象
let stack = new Stack()
//2.递归
while (decNumber > 0){
//2.1 获取余数,并放到栈中
stack.push(decNumber % 2)
//2.2 获取整除后的结果,作为下一次的运行的数字
decNumber = Math.floor(decNumber / 2)
}
//3、从栈中去除0和1
let binaryString = ""
while(!stack.isEmpty()){
binaryString += stack.pop()
}
return binaryString
}
队列:先进先出:只允许后端加入数据前端删除数据(不是只前后端分离,是指队列的前端和后端)
(例如:排队买票,先买先离开队伍)
// 封装队列
function Queue() {
// 属性
this.items = []
// 方法
// 前两个方法体现了队列的先进先出的特性
// enqueue(element):向队列尾部添加一个或者多个项
Queue.prototype.enqueue=function (element) {
this.items.push(element)
}
// dequeue():移除第一个项,并返回这个元素
Queue.prototype.dequeue = function(){
return this.items.shift()
}
// front():返回队列中的第一个元素,也将是最先被移除的元素。队列不做任何变动(不移除元素,只返回元素信息--和Stack的peek()方法类似)
Queue.prototype.front = function(){
return this.items[0]
}
// isEmpty():如果队列中没有元素,则返回true,否则返回false
Queue.prototype.isEmpty = function(){
return this.items.length === 0
}
// size():返回队列中元素的个数
Queue.prototype.size = function(){
return this.items.length
}
// toString():将队列中的内容转为字符串的形式
Queue.prototype.toString = function(){
let resultString =''
for(let i=0;i<this.items.length;i++){
resultString += this.items[i]+''
}
return resultString;
}
}
//使用队列
let Queue = new Queue()
Queue.enqueue('abc');
Queue.enqueue('cba');
Queue.enqueue('nba');
alert(Queue)
封装优先级队列:所谓的优先级队列就是指特定的值的优先级比较高
//封装队列
function PriorityQueue(){
//内部再次创建一个类,在内部使用
function QueueElement(element,priority){
this.ele = element;
this.pri = priority;
}
let items = []
PriorityQueue.prototype.enqueue = function(element,priority){
//1、创建QueueElement实例对象
let queueElemtnt = new QueueElement(elemet,priority)
if(this.items.length===0){
this.items.push(queueElement)
}else{
let isAdd = false
for(let i=0;i<this.items.lengtg;i++){
if(queueElemnt.pri<this.items[i].priority){
this.items.splice(i,0,queueElement)
isAdd = true
return;
}
}
if(!isAdd){
this.items.push(queueElement)
}
}
}
}
//测试队列
let priQueue = new PriorityQueue()
击鼓传花算法:
游戏规则:就是你玩的击鼓传话的规则
修改成算法的规则:
1、几个朋友玩这个游戏,围成一圈,开始数数,数到某个数字的人自动淘汰
2、最后剩下的这个人将获得胜利,请问最后剩下的是原来那个位置上的人
封装一个基于队列的函数
1、参数,所有参与人的姓名,基于数字
2、最终剩下的一个人的名字
function Queue() {
// 属性
this.items = []
// 方法 :前两个方法体现了队列的先进先出的特性
// enqueue(element):向队列尾部添加一个或者多个项
Queue.prototype.enqueue=function (element) {
this.items.push(element)
}
// dequeue():移除第一个项,并返回这个元素
Queue.prototype.dequeue = function(){
return this.items.shift()
}
// front():返回队列中的第一个元素,也将是最先被移除的元素。队列不做任何变动(不移除元素,只返回元素信息--和Stack的peek()方法类似)
Queue.prototype.front = function(){
return this.items[0]
}
// isEmpty():如果队列中没有元素,则返回true,否则返回false
Queue.prototype.isEmpty = function(){
return this.items.length === 0
}
// size():返回队列中元素的个数
Queue.prototype.size = function(){
return this.items.length
}
// toString():将队列中的内容转为字符串的形式
Queue.prototype.toString = function(){
let resultString =''
for(let i=0;i<this.items.length;i++){
resultString += this.items[i]+''
}
return resultString;
}
}
//击鼓传花算法
function PassGame(nameList,num){
// 创建队列
let queue = new Queue()
// 将所有人加入队列中
for (let i = 0; i < nameList.length; i++) {
queue.enqueue(nameList[i])
}
// 开始数数字
// 不是num数字的时候重新加入队列的末尾
// 是num这个数字的时候,删除
// 循环:若size只剩下一个人时停止循环
while(queue.size() >1){
// 将不是num这个数字的人重新加入队列的末尾
for (let j = 0; j < num - 1; j++) {
queue.enqueue(queue.dequeue());
}
// 删除队列的第一个元素
queue.dequeue()
}
let endName = queue.front()
console.log('最后的人名:'+endName);
}
let names=["lilei","hanmeimei","madongmei","mashenmemei","madongshenme","shenme dongmei"]
this.PassGame(names,3)
链表学习:
function LinkedList() {
//内部节点类
function Node(data, next) {
this.data = data;
this.next = null;
}
//属性
let head = null;
this.length = 0; //链表长度
// append(element):向列表尾部添加一个新的项
LinkedList.prototype.append = function (ele) {
// 创建新节点
let newNode = new Node(ele);
//判断是否添加的是第一个节点
if (this.length === 0) {
this.head = newNode;
console.log(1);
} else {
// 让当前的current指向head,如果这个元素的next不为空就继续指向下一个元素的next,直到next为空
// 也就是找最后一个节点,因为最后一个节点的next为空
let current = this.head;
while (current.next) {
current = current.next;
}
// 然后向最后一个节点添加新的newNode
current.next = newNode;
console.log(2);
}
this.length += 1; //链长度加一
};
// insert(position,element):向列表的特定位置插入一个新的项
LinkedList.prototype.insert = function (position, ele) {
// 给position进行越界判断
// position不能为负数,不能超过链的长度
if (position < 0 || position > this.length) return false;
// 创建新节点
let newNode = new Node(ele);
// 判断插入位置是否为第一个节点
if (position === 0) {
newNode.next = this.head; //将原来第一个的节点指向当前newNode的next
this.head = newNode; //将head指向的下一个节点指向新的newNode的节点
} else {
let index = 0;
let previous = null;
let current = this.head;
while (index++ < position) {
previous = current;
current = current.next;
}
newNode.next = current;
previous.next = newNode;
}
this.length += 1;
return true;
};
// get(position):获取对应位置的元素
LinkedList.prototype.get = function (position) {
// 给position进行越界判断
// position不能为负数,不能超过链的长度
if (position < 0 || position >= this.length) return false;
// 获取对应的数据
let current = this.head;
let index = 0;
while (index < position) {
current = current.next;
index++;
}
return current.data;
};
// indexOf(element):返回元素在列表中的索引,如果列表中没有该元素则返回-1
LinkedList.prototype.indexOf = function (data) {
let current = this.head;
let index = 0;
while (current) {
if ((current.data = data)) {
return index;
}
index++;
current = current.next;
}
// 没有找到对应的时候,返回-1
return -1;
};
// update(position):修改某个位置的元素
LinkedList.prototype.update = function (position, newData) {
if (position < 0 || position >= this.length) return false;
let index = 0;
let current = this.head;
while (index < position) {
current = current.next;
index++;
}
current.data = newData;
};
// removeAt(position):从列表的特定位置移除一项
LinkedList.prototype.removeAt = function (position) {
if (position < 0 || position >= this.length) return null;
let current = this.head;
// 判断是否删除第一个节点
if (position === 0) {
this.head = this.head.next; //直接指向下一个节点即可
} else {
let index = 0;
let previous = null;
while (index < position) {
previous = current;
current = current.next;
index++;
}
previous.next = current.next;
this.length -= 1;
return current.data;
}
};
// remove(element):从列表中移除一项
LinkedList.prototype.remove = function (data) {
// 1、首先获取当前的位置
let position = this.indexOf(data);
// 2、其次将其删除
return this.removeAt(position);
};
// isEmpty():如果链表中不包含任何元素,则返回true,若是有元素就返回false
LinkedList.prototype.isEmpty = function () {
return this.length === 0;
};
// size():返回链表包含的元素个数,和数组的length一样
LinkedList.prototype.size = function () {
return this.length;
};
// toString():由于列表项使用Node类,就需要重写继承自JavaScript对象默认的toString方法,让其只输出元素的值
LinkedList.prototype.toString = function () {
// 定义变量
let current = this.head;
let listString = "";
// 循环获取每个节点,并将其转为string
while (current) {
listString += current.data + "";
current = current.next;
}
return listString;
};
}
//测试代码
let list = new LinkedList();
list.append("abc ");
双向链表学习:
function DoublyLinkedList() {
// 创建内部节点
function Node(data) {
this.data = data;
this.next = null;
this.prev = null;
}
//创建属性
this.head = null;
this.tail = null;
this.length = 0;
// append(ele):向列表尾部添加一个新的项
DoublyLinkedList.prototype.append = function (data) {
// 1、根据data创建节点
let newNode = new Node(data);
// 2、判断添加的是否是第一个节点
if (this.length === 0) {
this.head = newNode;
this.tail = newNode;
} else {
newNode.prev = this.tail;
this.tail.next = newNode;
this.tail = newNode;
}
// 3、长度加一
this.length++;
};
// insert(position,ele):向列表的特定位置插入一个新的项
DoublyLinkedList.prototype.insert = function (position, ele) {
// 越界判断
if (position < 0 || position > this.length) return false;
// 创建节点
let newNode = new Node(ele);
// 判断原有的链表是否为空
if (this.length === 0) {
this.head = newNode;
this.tail = newNode;
} else {
// 判断是否position为0
if (position === 0) {
// 原来的节点向后移动一位,所以prev指向新的节点
this.head.prev = newNode;
// 新节点的下一位指向原来的节点
newNode.next = this.head;
// 现在的第一个的位置为新的节点
this.head = newNode;
} else if (position === this.length) {
// position为最后一个节点
newNode.prev = this.tail;
this.tail.next = newNode;
this.tail = newNode;
} else {
let current = this.head;
let index = 0;
while (index < position) {
current = current.next;
index++;
}
// 找到当前的current的节点后,修改指针
newNode.next = current;
newNode.prev = current.prev;
current.prev.next = newNode;
current.prev = newNode;
}
}
this.length++;
return true;
};
// get(position):获取对应位置的元素
DoublyLinkedList.prototype.get = function (position) {
if (position < 0 || position >= this.length) return null;
// 获取元素
let current = this.head;
let index = 0;
while (index < position) {
current = current.next;
index++;
}
return current.data;
};
// indexOf(ele):返回元素在列表中的索引。如果列表中没有该元素则返回-1
DoublyLinkedList.prototype.indexOf = function (ele) {
// 定义变量
let current = this.head;
let index = 0;
// 查找当前的节点
while (current) {
if (current.data === data) {
return index;
}
current = current.next;
index++;
}
return -1;
};
// update(position,ele):修改某个位置的元素
DoublyLinkedList.prototype.update = function (position, ele) {
// 判断越界
if (position < 0 || position >= this.length) return false;
// 寻找当前的节点
let current = this.head;
let index = 0;
while (index < position) {
current = current.next;
index++;
}
// 修改当前的数据
current.data = ele;
return true;
};
// removeAt(position):从列表中的特定位置移除一项
DoublyLinkedList.prototype.removeAt = function (position) {
// 判断越界
if (position < 0 || position >= this.length) return null;
// 判断是否只有一个节点
if (this.length === 0) {
//当只有一个节点时,删除该节点即head和tail都指向null
this.head = null;
this.tail = null;
} else {
if (position === 0) {
//判断是否删除的是第一个节点
this.head.next.prev = null; //删除第一个节点时,第二个节点的prev指向null
this.head = this.head.next; //head指向第二个节点
} else if ((position = this.length - 1)) {
//判断是否为最后一个节点
this.tail.prev.next = null; //如果是最后一个节点,此时的倒数第二个的next指向null
this.tail = this.tail.prev; //此时的tail指向倒数第二个---倒二变成现在倒一
} else {
// 定义变量
let index = 0;
let current = this.head;
// 找到当前的节点
while (index < position) {
current = current.next;
index++;
}
// 将当前节点的前一个节点的next指向现在节点的下一个,也就会跳过当前节点
current.prev.next = current.next;
// 将当前节点的下一个节点的prev指向现在节点的上一个,也就是跳过当前节点
current.next.prev = current.prev;
// 当跳过之后就会自动回收没有用到的节点
}
}
this.length -1
return current.data
};
// remove(ele):从列表中的特定位置移除一项
DoublyLinkedList.prototype.remove = function (ele) {
// 通过前面的indexof找到下标
let index = this.indexOf(ele);
// 通过下标删除该节点
return this.removeAt(index)
};
// isEmpty():如果链表中不包括任何元素就返回ture,否则返回false
DoublyLinkedList.prototype.isEmpty = function () {
return this.length === 0;
};
// size():返回链表中包含的元素个数
DoublyLinkedList.prototype.size = function () {
return this.length;
};
// toString():由于链表中使用了Node类,就需要重写继承自JavaScript对象默认的toString方法,让其只输出元素的值
DoublyLinkedList.prototype.toString = function () {
return this.backWardString();
};
// forWardString():返回正向遍历的节点字符串形式
DoublyLinkedList.prototype.forWardString = function () {
// 定义变量
let current = this.taillet;
let resultString = "";
// 依次向前遍历,获取每一个的节点
while (current) {
resultString += current.data + "";
current = current.prev;
}
return resultString;
};
// backWardString():返回反向遍历的节点字符串形式
DoublyLinkedList.prototype.backWardString = function () {
// 定义变量
let current = this.head;
let resultString = "";
// 依次向后遍历,获取每一个节点
while (current) {
resultString += current.data + "";
current = current.next;
}
return resultString;
};
}