数据结构学习-栈、队列、单向链表、双向链表

223 阅读9分钟

数据结构学习笔记

栈学习:

img

//栈:后进先出,后面进入栈中的数据要先取出才能操作之前进入栈中的数据
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
}

队列:先进先出:只允许后端加入数据前端删除数据(不是只前后端分离,是指队列的前端和后端)

img

(例如:排队买票,先买先离开队伍)

// 封装队列  
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)

链表学习:

img

  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 ");

双向链表学习:

img

 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;
        };
      }