算法.JS.1.数据结构

179 阅读3分钟

1. 列表-list

  1. 学习算法-面试和开发必备;
  2. 列表-待办事项;
  3. 使用-元素不多,不需很长排序,不需复杂查找;
  4. 概念-有序的数据;
  5. 迭代器优点-增删比 for 灵活;
  6. 空列表-不包含任何元素的列表;
  7. 列表函数-List, 列表方法-append find remove length toString insert clear contains front end prev next moveTo getElement currPos;
function List() {
  this.listSize = 0; 
  this.pos = 0; // 列表当前位置
  this.dataStore = []; // 初始化一个空数组用来保存表元素
  this.clear = clear; // 清空列表中的所有元素
  this.find = find; // 查找元素
  this.toString = toString; // 返回列表字符串形式
  this.insert = insert; // 在现有元素中插后插入新元素
  this.append = append; // 在列表元素末尾增加新元素
  this.remove = remove; // 从列表元素中删除元素
  this.front = front; // 从列表当前位置移动到第一个元素
  this.end = end; // 从列表当前位置移动到最后一个位置
  this.prev = prev; // 将当前位置后移一位
  this.next = next; // 将当前位置前移一位
  this.length = length; // 列表包含元素的个数
  this.currPos = currPos; // 返回列表当前位置
  this.moveTo = moveTo; // 将当前位置移动到指定位置
  this.getElement = getElement; // 显示当前的元素
  this.contains = contains; // 是否包含该元素
}
function append(element) {
  this.dataStore[this.listSize++] = element;
}
function find(element) {
  // 此处++应置于之前 以便返回正确的索引
  for (let i = 0; i < this.dataStore.length; ++i) {
    if (this.dataStore[i] === element) {
      return i;
    }
  }
  return -1;
}
function remove(element) {
  var foundAt = this.find(element);
  if (foundAt > -1) {
    this.dataStore.slice(foundAt, 1);
    --this.listSize;
    return;
  }
  return false;
}
function length() {
  return this.listSize;
}
function toString() {
  return this.listSize;
}
function insert(element, after) {
  var insertPos = this.find(after);
  if (insertPos > -1) {
    this.dataStore.splice(insertPos + 1, 0, element);
    --this.listSize;
    return true;
  }
  return false;
}
function clear() {
  delete this.dataStore;
  this.dataStore.length = 0; // 创建一个空数组
  this.listSize = this.pos = 0;
}
function contains() {
  // 此处++应置于之前 以便返回正确的索引
  for (let i = 0; i < this.dataStore.length; ++i) {
    if (this.dataStore[i] === element) {
      return true;
    }
  }
  return false;
}
function front() {
  this.pos = 0;
}
function end() {
  this.pos = this.listSize - 1;
}
function prev() {
  if (this.pos > 0) {
    --this.pos;
  }
}
function next() {
  if (this.pos < this.listSize) {
    ++this.pos;
  }
}
function currPos() {
  return this.pos;
}
function moveTo(position) {
  this.pos = position;
}
function getElement() {
  return this.dataStore[this.pos];
}
let list = new List();
list.append("小红");
list.append("小黄");
list.append("小蓝");
list.next();
// console.log(list.getElement());
for (list.front(); list.currPos() < list.length(); list.next()) {
  console.log(list.getElement()); // 小红 小黄 小蓝
}

2. 栈-stack

  • 栈-后入先出的数据结构
  • 栈是特殊列表-只能在栈顶进行赠删
  • 栈的例子-生活,洗盘子 代码,函数调用
  • 后入先出英文-LIFO last-in-fast-out
  • 栈的代码表示-Stack 方法 push pop peek length clear
function Stack() {
  this.dataStore = []; // 保存栈内元素
  this.top = 0; // 标记可以插入新元素的位置 栈内压入元素该变量变大 推出元素变量变小
  this.push = push; // 入栈操作
  this.pop = pop; // 出栈操作
  this.peek = peek; // 返回栈顶元素
  this.length = length; // 栈的长度
  this.clear = clear; // 清空栈
}
function push(ele) {
  this.dataStore[this.top++] = ele;
}
function pop() {
  return this.dataStore[--this.top];
}
function peek() {
  return this.dataStore[this.top - 1];
}
function length() {
  return this.top;
}
function clear() {
  this.top = 0;
}
let stack = new Stack();
stack.push("小红");
stack.push("小黄");
stack.push("小蓝");
console.log("栈的长度", stack.length());
console.log("栈顶", stack.peek());
console.log("出栈", stack.pop());
console.log("出栈", stack.pop());
console.log("出栈", stack.pop());
  • 利用栈实现回文算法isPalindrome-创建空栈s,参数遍历入栈push,创建新字符串为空rword,while 遍历栈列表,新字符串拼接每次出栈结果pop,返回新字符串与参数相等比较结果即为是否回文
/**
 * 回文算法 racecar
 * @param {String} word
 */
function isPalindrome(word) {
  var s = new Stack();
  for (var i = 0; i < word.length; i++) {
    s.push(word[i]);
  }
  var rword = "";
  while (s.length() > 0) {
    rword += s.pop();
  }
  if (rword === word) {
    return true;
  } else {
    return false;
  }
}
var word = "racecar";
console.log(isPalindrome(word));

3. 队列-queue

  • 队列-先入先出的数据结构
  • 实例-现实,银行排队
  • 队列描述-从队尾入队,从队首出队
  • 优先队列-例子,急诊
  • 队列代码-Queue 队列方法-enqueue,dequeue,front,back,empty,toString
function Queue() {
  this.dataStore = []; // 保存队内元素
  this.enqueue = enqueue; // 向队尾增加一个元素
  this.dequeue = dequeue; // 删除队首元素
  this.front = front; // 读取队首元素
  this.back = back; // 读取队尾元素
  this.toString = toString; // 展示队列中所有元素
  this.empty = empty; // 判断队列是否为空
}
function enqueue(ele) {
  this.dataStore.push(ele);
}
function dequeue() {
  return this.dataStore.shift();
}
function front() {
  return this.dataStore[0];
}
function back() {
  return this.dataStore[this.dataStore.length - 1];
}
function empty() {
  return this.dataStore.length === 0;
}
function toString() {
  var reStr = "";
  for (var i = 0; i < this.dataStore.length; i++) {
    reStr += this.dataStore[i] + "\n";
  }
  return reStr;
}
var queue = new Queue();
queue.enqueue("小红");
queue.enqueue("小黄");
queue.enqueue("小蓝");
console.log(queue.toString());
console.log("出队:", queue.dequeue(), "出队结果:", queue.toString());

// 方块舞-舞伴配对
var manDancers = new Queue();
manDancers.enqueue("小张");
manDancers.enqueue("小李");
var womanDancers = new Queue();
womanDancers.enqueue("小红");
womanDancers.enqueue("小黄");
function getDancers() {
  return "♂" + manDancers.dequeue() + "♀" + womanDancers.dequeue();
}
console.log("一队舞伴:", getDancers());
console.log("二队舞伴:", getDancers());

// 急诊病患优先出列-优先队列
function Patient(name, code) {
  this.name = name;
  this.code = code;
}

function dequeuePatient() {
  var priority = 0;
  for (var i = 0; i < this.dataStore.length; ++i) {
    if (this.dataStore[i].code > this.dataStore[priority].code) {
      priority = i;
    }
  }
  return this.dataStore.splice(priority, 1);
}
function toStringPatient() {
  var reStr = "";
  for (var i = 0; i < this.dataStore.length; i++) {
    reStr += this.dataStore[i].name + " code: " + this.dataStore[i].code + "\n";
  }
  return reStr;
}

let pa1 = new Patient("小红", 1);
let pa2 = new Patient("小黄", 8);
let pa3 = new Patient("小蓝", 3);
let pa4 = new Patient("小张", 5);
let pa5 = new Patient("小李", 1);
let pa6 = new Patient("小王", 7);

let queuePatient = new Queue();
queuePatient.toString = toStringPatient;
queuePatient.dequeue = dequeuePatient;
queuePatient.enqueue(pa1);
queuePatient.enqueue(pa2);
queuePatient.enqueue(pa3);
queuePatient.enqueue(pa4);
queuePatient.enqueue(pa5);
queuePatient.enqueue(pa6);
console.log("第一个被诊治的:", queuePatient.dequeue());
console.log("剩余队列:\n", queuePatient.toString());
console.log("第二个被诊治的:", queuePatient.dequeue());
console.log("剩余队列:\n", queuePatient.toString());

4. 链表-列表中元素指向下一个元素,组成链条 使用链表原因-数组不是组织数据最佳结构 链表优点-插入删除速度比数组快,只需要改变元素指向来进行元素增删 链表实例-现实自行车链条 双向链表-链表中元素之间指向对方;

5. 字典-dictionary

  • 字典-键-值对形式为元素存储的列表
  • 字典例子-电话簿,通过名字查找手机号;
  • 字典代码-Dictionary,方法-add find remove showAll count clear; 排序-根据键值 sort;
function Dictionary() {
  this.dataStore = [];
  this.add = add;
  this.find = find;
  this.remove = remove;
  this.showAll = showAll;
  this.count = count;
  this.clear = clear;
}
function add(key, value) {
  this.dataStore[key] = value;
}
function find(key) {
  return this.dataStore[key];
}
function remove(key) {
  delete this.dataStore[key];
}
function showAll() {
  var dataKeys = Object.keys(this.dataStore).sort();
  for (var key in dataKeys) {
    console.log(dataKeys[key] + "-->" + this.dataStore[dataKeys[key]]);
  }
}
function count() {
  return Object.keys(this.dataStore).length;
}
function clear() {
  var dataKeys = Object.keys(this.dataStore);
  for (var key in dataKeys) {
    delete this.dataStore[dataKeys[key]];
  }
}
var d = new Dictionary();
d.add("小红", 18);
d.add("小黄", 19);
d.add("小蓝", 20);
console.log("小红", d.find("小红"));
d.showAll();
d.remove("小红");
console.log("个数", d.count());
d.clear();
console.log("个数", d.count());

6. 散列-HashTable

  • 散列-数组长度预先设定,将键均匀分布的特殊列表;
  • 碰撞-两个键相同的情况;
  • 开链法-两个键相同保存位置一样。开辟第二数组;
  • 线性探测法-开放寻址散列,查找散列位置如果没有当前位置没有继续寻找下一个位置。存储数据较大较适合。
  • 方法选择-数组大小>=1.5数据(开链法),数组大小>=2数据(线性探索法);
  • 防止碰撞-设置质数长度数组;
  • 散列-普通
function HashTable() {
  this.table = new Array(137);
  this.simpleHash = simpleHash;
  this.put = put;
  this.get = get;
  this.showDistro = showDistro;
  this.betterHash = betterHash;
}
/**
 * 除留余数法
 * @param {String} data
 */
function simpleHash(data) {
  var total = 0;
  for (var i = 0; i < data.length; i++) {
    total += data.charCodeAt(i);
  }
  return total % this.table.length;
}
function put(data) {
  var pos = this.betterHash(data);
  this.table[pos] = data;
}
function get(key) {
  return this.table[this.betterHash(key)];
}
function showDistro() {
  var n = 0;
  for (var i = 0; i < this.table.length; i++) {
    if (this.table[i] != undefined) {
      console.log("键值是-》" + i + "值是【" + this.table[i] + "】");
    }
  }
}
// 防止碰撞
function betterHash(data) {
  var H = 31;
  var total = 0;
  for (let i = 0; i < data.length; i++) {
    total += H * total + data.charCodeAt(i);
  }
  if (total < 0) {
    total += this.table.length - 1;
  }
  return total % this.table.length;
}
var hd = new HashTable();
hd.put("China");
hd.put("Japan");
hd.put("America");
hd.put("niCha");
hd.put("12345");
hd.showDistro();
  • 散列-开链法
function HashTable() {
  this.table = new Array(137);
  this.simpleHash = simpleHash;
  this.put = put;
  this.get = get;
  this.showDistro = showDistro;
  this.betterHash = betterHash;
  this.buildChains = buildChains;
}
// 开链法
function buildChains() {
  for (let i = 0; i < this.table.length; i++) {
    this.table[i] = new Array();
  }
}
/**
 * 除留余数法
 * @param {String} data
 */
function simpleHash(data) {
  var total = 0;
  for (var i = 0; i < data.length; i++) {
    total += data.charCodeAt(i);
  }
  return total % this.table.length;
}
function put(data) {
  // 开链法插入
  var pos = this.simpleHash(data);
  var index = 0;
  if (this.table[pos][index] == undefined) {
    this.table[pos][index] = data;
    index++;
  } else {
    while (this.table[pos][index] != undefined) {
      ++index;
    }
    this.table[pos][index] = data;
  }
}
function get(key) {
  return this.table[this.simpleHash(key)];
}
function showDistro() {
  var n = 0;
  for (var i = 0; i < this.table.length; i++) {
    if (this.table[i][0] != undefined) {
      console.log("键值是-》" + i + "值是【" + this.table[i] + "】");
    }
  }
}
function betterHash(data) {
  var H = 31;
  var total = 0;
  for (let i = 0; i < data.length; i++) {
    total += H * total + data.charCodeAt(i);
  }
  if (total < 0) {
    total += this.table.length - 1;
  }
  return total % this.table.length;
}
var hd = new HashTable();
hd.buildChains();
hd.put("China");
hd.put("Japan");
hd.put("America");
hd.put("niCha");
hd.put("12345");
hd.showDistro(); 
  • 散列-线性探索法
function HashTable() {
  this.table = new Array(137);
  this.simpleHash = simpleHash;
  this.put = put;
  this.get = get;
  this.showDistro = showDistro;
}
/**
 * 除留余数法
 * @param {String} data
 */
function simpleHash(data) {
  var total = 0;
  for (var i = 0; i < data.length; i++) {
    total += data.charCodeAt(i);
  }
  return total % this.table.length;
}
function put(data) {
  // 线性插入,找到空位插入,找不到空位向后找到空位为止
  var pos = this.simpleHash(data);
  if (this.table[pos] == undefined) {
    this.table[pos] = data;
  } else {
    while (this.table[pos] != undefined) {
      pos++;
    }
    this.table[pos] = data;
  }
}
function get(key) {
  var hash = this.simpleHash(key);
  console.log(hash);
  for (var i = 0; i < this.table.length; i++) {
    if (this.table[i] == key) {
      return i;
    }
  }
  return undefined;
}
function showDistro() {
  var n = 0;
  for (var i = 0; i < this.table.length; i++) {
    if (this.table[i] != undefined) {
      console.log("键值是-》" + i + "值是【" + this.table[i] + "】");
    }
  }
}
var hd = new HashTable();
hd.put("China");
hd.put("Japan");
hd.put("America");
hd.put("niCha");
hd.put("12345");
console.log("niCha的位置", hd.get("niCha"));
hd.showDistro();

7. 集合-Set

  • 集合-包含不同元素的数据结构;
function Set() {
  this.dataStore = new Array();
  this.add = add;
  this.remove = remove;
  this.show = show;
  this.union = union;
  this.intersect = intersect;
  this.difference = difference;
  this.subset = subset;
  this.contains = contains;
  this.size = size;
}
function add(data) {
  if (this.dataStore.indexOf(data) != -1) return false;
  this.dataStore.push(data);
}
function remove(data) {
  var pos = this.dataStore.indexOf(data);
  if (pos == -1) return false;
  this.dataStore.splice(pos, 1);
}
function show() {
  console.log(this.dataStore);
  return this.dataStore;
}

let names = new Set();
names.add("小红");
names.add("小红");
names.add("小黄");
names.add("小蓝");
names.add("老王");
// names.show();
// 交集-intersect 并集-union 补集-difference 子集-subset;
function contains(data) {
  return this.dataStore.indexOf(data) != -1;
}
function union(set) {
  var temSet = new Set();
  for (let i = 0; i < this.dataStore.length; i++) {
    temSet.add(this.dataStore[i]);
  }
  for (let i = 0; i < set.dataStore.length; i++) {
    if (!temSet.contains(set.dataStore[i])) {
      temSet.dataStore.push(set.dataStore[i]);
    }
  }
  return temSet;
}
function intersect(set) {
  var temSet = new Set();
  for (let i = 0; i < this.dataStore.length; i++) {
    if (set.contains(this.dataStore[i])) {
      temSet.add(this.dataStore[i]);
    }
  }
  return temSet;
}
function difference(set) {
  var temSet = new Set();
  for (let i = 0; i < this.dataStore.length; i++) {
    if (!set.contains(this.dataStore[i])) {
      temSet.add(this.dataStore[i]);
    }
  }
  return temSet;
}
function size() {
  return this.dataStore.length;
}
function subset(set) {
  if (this.size() < set.size()) return false;
  for (let i = 0; i < set.dataStore.length; i++) {
    if (!this.contains(set.dataStore[i])) {
      return false;
    }
  }
  return true;
}
let cit = new Set();
cit.add("1");
cit.add("2");
cit.add("3");
cit.add("小红");
cit.union(names).show();
cit.intersect(names).show();
cit.difference(names).show();
let it = new Set();
it.add("1");
console.log(cit.subset(it));

8. 二叉树-BST

  • 二叉树-非线性分层数据结构;
  • 特点-子节点不超过两个;
  • 二叉查找树-特殊二叉树,较小的值保存在左节点;
  • 二叉查找树代码
function Node(data, left, right) {
  this.data = data;
  this.left = left;
  this.right = right;
  this.show = show;
}
function show() {
  return this.data;
}
function BST() {
  this.root = null;
  this.insert = insert;
  this.inOrder = inOrder;
  this.getSmallest = getSmallest;
  this.getMax = getMax;
  this.find = find;
  this.remove = remove;
}
function insert(data) {
  var n = new Node(data, null, null);
  if (this.root == null) {
    this.root = n;
  } else {
    var current = this.root;
    var parent;
    while (true) {
      parent = current;
      if (data < current.data) {
        current = current.left;
        if (current == null) {
          parent.left = n;
          break;
        }
      } else {
        current = current.right;
        if (current == null) {
          parent.right = n;
          break;
        }
      }
    }
  }
}
function inOrder(node) {
  if (node != null) {
    inOrder(node.left);
    console.log(node.data);
    inOrder(node.right);
  }
}
function getSmallest(root) {
  var current = this.root || root;
  while (current.left != null) {
    current = current.left;
  }
  console.log(current.data);
  return current;
}
function getMax() {
  var current = this.root || root;
  while (current.right != null) {
    current = current.right;
  }
  console.log(current.data);
  return current;
}
function find(data) {
  var current = this.root;
  while (current.data != null) {
    if (data == current.data) {
      return current;
    } else if (data < current.data) {
      current = current.left;
    } else if (data > current.data) {
      current = current.right;
    }
  }
  return null;
}
function remove(data) {
  removeNode(this.root, data);
}
function removeNode(node, data) {
  if (node == null) return null;
  if (node.data == data) {
    if (node.left == null && node.right == null) {
      return null;
    }
    if (node.left == null) {
      return node.right;
    }
    if (node.right == null) {
      return node.left;
    }
    var tempNode = getSmallest(node.right);
    node.data = tempNode.data;
    node.right = removeNode(node.right, tempNode.data);
    return node;
  } else if (data < node.data) {
    node.left = removeNode(node.left, data);
    return node;
  } else {
    node.right = removeNode(node.right, data);
    return node;
  }
}
var nums = new BST();
nums.insert(50);
nums.insert(10);
nums.insert(19);
nums.insert(30);
nums.insert(99);
nums.insert(55);
nums.insert(11);
nums.inOrder(nums.root);
console.log("-------------");
nums.getSmallest();
nums.getMax();
console.log("-------------");
console.log(nums.find(99));
console.log("-------------");
nums.remove(11);
nums.inOrder(nums.root);