js数据结构

列表

列表是一组有序的数据。每个列表中的数据项称为元素。在 JavaScript 中,列表中的元素可以是任意数据类型。列表中可以保存多少元素并没有事先限定,实际使用时元素的数量受到程序内存的限制。

列表的抽象数据类型定义
listSize (属性) 列表的元素个数
pos (属性) 列表的当前位置
length (属性) 返回列表中元素的个数
clear (方法) 清空列表中的所有元素
toString (方法) 返回列表的字符串形式
getElement (方法) 返回当前位置的元素
insert (方法) 在现有元素后插入新元素
append (方法) 在列表的末尾添加新元素
remove (方法) 从列表中删除元素
front (方法) 将列表的当前位置设移动到第一个元素
end (方法) 将列表的当前位置移动到最后一个元素
prev (方法) 将当前位置后移一位
next (方法) 将当前位置前移一位
currPos (方法) 返回列表的当前位置
moveTo (方法) 将当前位置移动到指定位置
再加上this.dataStore = [];//使用一个数组dataStore 来存储元素。
位置用数组下标表示,本质为对数组的操作
使用迭代器访问列表

for(names.front(); names.currPos() < names.length(); names.next()) {
print(names.getElement());
}

栈是一种特殊的列表,栈内的元素只能通过列表的一端访问,这一端称为栈顶。
我们用数组 dataStore 保存栈内元素,构造函数将其初始化为一个空数组。变量 top 记录栈顶位置,被构造函数初始化为 0,表示栈顶对应数组的起始位置 0。如果有元素被压入栈,该变量的值将随之变化。

function Stack() {
  this.dataStore = [];
  this.top = 0;
  this.push = push;
  this.pop = pop;
  this.peek = peek;
  this.clear = clear;
  this.length = length;
}
function push(element) {
  this.dataStore[this.top++] = element;
}
function peek() {
  return this.dataStore[this.top - 1];
 
}
function pop() {
  return this.dataStore[--this.top];
}
function clear() {
  this.top = 0;
}
function length() {
  return this.top;
}

队列

队列是一种列表,不同的是队列只能在队尾插入元素,在队首删除元素。队列用于存储按顺序排列的数据,先进先出,

function Queue() {
  this.dataStore = [];
  this.enqueue = enqueue;
  this.dequeue = dequeue;
  this.front = front;
  this.back = back;
  this.toString = toString;
  this.empty = empty;
}
enqueue() 方法向队尾添加一个元素:
function enqueue(element) {
  this.dataStore.push(element);
}
dequeue() 方法删除队首的元素:
function dequeue() {
  return this.dataStore.shift();
}
可以使用如下方法读取队首和队尾的元素:
function front() {
  return this.dataStore[0];
}
function back() {
  return this.dataStore[this.dataStore.length - 1];
}
还需要 toString() 方法显示队列内的所有元素:
function toString() {
  var retStr = "";
  for (var i = 0; i < this.dataStore.length; ++i) {
    retStr += this.dataStore[i] + "\n";
  }
  return retStr;
}
最后,需要一个方法判断队列是否为空:
function empty() {
  if (this.dataStore.length == 0) {
    return true;
  }
  else {
    return false;
  }
}

链表

链表是由一组节点组成的集合。每个节点都使用一个对象的引用指向它的后继。指向另一个节点的引用叫做链。
Node 类和 LList 类

function Node(element) {
  this.element = element;
  this.next = null;
}
function LList() {
  this.head = new Node("head");
  this.find = find;
  this.insert = insert;
  this.display = display;
  this.findPrevious = findPrevious;
  this.remove = remove;
}
function remove(item) {
  var prevNode = this.findPrevious(item);
  if (!(prevNode.next == null)) {
    prevNode.next = prevNode.next.next;
  }
}
function findPrevious(item) {
  var currNode = this.head;
  while (!(currNode.next == null) &&
    (currNode.next.element != item)) {
    currNode = currNode.next;
  }
  return currNode;
}
function display() {
  var currNode = this.head;
  while (!(currNode.next == null)) {
    print(currNode.next.element);
    currNode = currNode.next;
  }
}
function find(item) {
  var currNode = this.head;
  while (currNode.element != item) {
    currNode = currNode.next;
  }
  return currNode;
}
function insert(newElement, item) {
  var newNode = new Node(newElement);
  var current = this.find(item);
  newNode.next = current.next;
  current.next = newNode;
}

双向链表 LList 类

function Node(element) {
  this.element = element;
  this.next = null;
  this.previous = null;
}
function LList() {
  this.head = new Node("head");
  this.find = find;
  this.insert = insert;
  this.display = display;
  this.remove = remove;
  this.findLast = findLast;
  this.dispReverse = dispReverse;
}
function dispReverse() {
  var currNode = this.head;
  currNode = this.findLast();
  while (!(currNode.previous == null)) {
    print(currNode.element);
    currNode = currNode.previous;
  }
}
function findLast() {
  var currNode = this.head;
  while (!(currNode.next == null)) {
    currNode = currNode.next;
  }
  return currNode;
}
function remove(item) {
  var currNode = this.find(item);
  if (!(currNode.next == null)) {
  
    currNode.previous.next = currNode.next;
    currNode.next.previous = currNode.previous;
    currNode.next = null;
    currNode.previous = null;
  }
}

function display() {
  var currNode = this.head;
  while (!(currNode.next == null)) {
    print(currNode.next.element);
    currNode = currNode.next;
  }
}
function find(item) {
  var currNode = this.head;
  while (currNode.element != item) {
    currNode = currNode.next;
  }
  return currNode;
}
function insert(newElement, item) {
  var newNode = new Node(newElement);
  var current = this.find(item);
  newNode.next = current.next;
  newNode.previous = current;
  current.next = newNode;
}

循环链表

Node类:head.next=head
function LList() {
  this.head = new Node("head");
  this.head.next = this.head;
  this.find = find;
  this.insert = insert;
  this.display = display;
  this.findPrevious = findPrevious;
  this.remove = remove;
}

字典

字典是一种以键 - 值对形式存储数据的数据结构,就像电话号码簿里的名字和电话号码一样。要找一个电话时,先找名字,名字找到了,紧挨着它的电话号码也就找到了。这里的键是指你用来查找的东西,值是查找得到的结果。

function Dictionary() {
  this.add = add;
  this.datastore = new Array();
  this.find = find;
  this.remove = remove;
  this.showAll = showAll;
}
function add(key, value) {
  this.datastore[key] = value;
}
function find(key) {
  return this.datastore[key];
}
function remove(key) {
  delete this.datastore[key];
}
function showAll() {
  for (var key in Object.keys(this.datastore)) {
    print(key + " -> " + this.datastore[key]);
  }
}
function count() {
  var n = 0;
  for each(var key in Object.keys(this.datastore)) {
    ++n;
  }
  return n;
}
function clear() {
  for each(var key in Object.keys(this.datastore)) {
    delete this.datastore[key];
  }
}

散列表

在这里插入图片描述

function HashTable() {
    this.table = new Array(137);
    this.simpleHash = simpleHash;
    this.betterHash = betterHash;
    this.showDistro = showDistro;
    this.put = put;
    //this.get = get;
}

function put(data) {
    var pos = this.betterHash(data);

    this.table[pos] = data;
}

function simpleHash(data) {
    var total = 0;
    for (var i = 0; i < data.length; ++i) {
        total += data.charCodeAt(i);
    }
    print("Hash value: " + data + " -> " + total);
    return total % this.table.length;
}

function showDistro() {
    var n = 0;
    for (var i = 0; i < this.table.length; ++i) {
        if (this.table[i] != undefined) {
            print(i + ": " + this.table[i]);
        }
    }
}

function betterHash(string) {
    const H = 37;
    var total = 0;
    for (var i = 0; i < string.length; ++i) {
        total += H * total + string.charCodeAt(i);
    }
    total = total % this.table.length;
    if (total < 0) {
        total += this.table.length - 1;
    }
    return parseInt(total);
}

对键值散列

function put(key, data) {
var pos = this.betterHash(key);
this.table[pos] = data;
}
function get(key) {
return this.table[this.betterHash(key)];
}

碰撞处理
1, 开链法

![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/a0d88773b72c31ee5e2e099f11990bc9.png)

//创建第二组数组
function buildChains() {
for (var i = 0; i < this.table.length; ++i) {
this.table[i] = new Array();
}
}


function showDistro() {
   var n = 0;
   for (var i = 0; i < this.table.length; ++i) {
       if (this.table[i][0] != undefined) {
           print(i + ": " + this.table[i]);
       }
   }
}

function put(key, data) {
   var pos = this.betterHash(key);
   var index = 0;
   if (this.table[pos][index] == undefined) {
       this.table[pos][index + 1] = data;
   }
   ++index;
else {
       while (this.table[pos][index] != undefined) {
           ++index;
       }
       this.table[pos][index + 1] = data;
   }
}

function get(key) {
   var index = 0;
   var hash = this.betterHash(key);
 
   if (this.table[pos][index] = key) {
       return this.table[pos][index + 1];
   }
   index += 2;
else {
       while (this.table[pos][index] != key) {
           index += 2;
       }
       return this.table[pos][index + 1];
   }
   return undefined;
}

线性探测法
第二种处理碰撞的方法是线性探测法。线性探测法隶属于一种更一般化的散列技术:开放寻址散列。当发生碰撞时,线性探测法检查散列表中的下一个位置是否为空。如果为空,就将数据存入该位置;如果不为空,则继续检查下一个位置,直到找到一个空的位置为止

在 HashTable 的构造函数中加入下面一行代码:
this.values = [];
在 put() 方法中使用线性探测技术:

function put(key, data) {
    var pos = this.betterHash(key);
    if (this.table[pos] == undefined) {
        this.table[pos] = key;
        this.values[pos] = data;
    }
    else {
        while (this.table[pos] != undefined) {
            pos++;
        }
       
        this.table[pos] = key;
        this.values[pos] = data;
    }
}

get() 方法先搜索键在散列表中的位置,如果找到,则返回数组 values 中对应位置上的数据;如果没有找到,则循环搜索,直到找到对应的键或者数组中的单元为 undefined 时,后者表示该键没有被存入散列表。代码如下:

function get(key) {
    var hash = -1;
    hash = this.betterHash(key);
    if (hash > -1) {
        for (var i = hash; this.table[hash] != undefined; i++) {
            if (this.table[hash] == key) {
                return this.values[hash];
            }
        }
    }
    return undefined;
}

集合

对集合的操作有下面几种。
并集 •
将两个集合中的成员进行合并,得到一个新集合。
交集 •
两个集合中共同存在的成员组成一个新的集合。
补集 •
属于一个集合而不属于另一个集合的成员组成的集合。
Set 类的实现基于数组,数组用来存储数据。我们还为上文提到的对集合的操作定义了相应的方法。下面是构造函数的定义:

function Set() {
this.dataStore = [];
this.add = add;
this.remove = remove;
this.size = size;
this.union = union;
this.intersect = intersect;
this.subset = subset;
this.difference = difference;
this.show = show;
}

二叉树和二叉查找树

Node 类

function Node(data, left, right) {
this.data = data;
this.left = left;
this.right = right;
this.show = show;
}

二叉树类

function BST() {
    this.root = null;
    this.insert = insert;
    this.inOrder = inOrder;
}
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;
                }
            }
        }
    }
}

遍历二叉树
1,中序(左中右)

function inOrder(node) {
    if (!(node == null)) {
        inOrder(node.left);
        putstr(node.show() + " ");
        inOrder(node.right);
    }
}

先序遍历的定义如下:(中左右)

function preOrder(node) {
if (!(node == null)) {
putstr(node.show() + " ");
preOrder(node.left);
preOrder(node.right);
}
}

后序遍历的访问路径(左右中)

postOrder() 方法的实现如下:
function postOrder(node) {
if (!(node == null)) {
postOrder(node.left);
postOrder(node.right);
putstr(node.show() + " ");
}
}

在二叉查找树上进行查找
对 BST 通常有下列三种类型的查找:
(1) 查找给定值;
(2) 查找最小值;
(3) 查找最大值。
从二叉查找树上删除节点
从 BST 中删除节点的第一步是判断当前节点是否包含待删除的数据,如果包含,则删除该节点;如果不包含,则比较当前节点上的数据和待删除的数据。如果待删除数据小于当前节点上的数据,则移至当前节点的左子节点继续比较;如果删除数据大于当前节点上的数据,则移至当前节点的右子节点继续比较。如果待删除节点是叶子节点(没有子节点的节点),那么只需要将从父节点指向它的链接
指向 null 。如果待删除节点只包含一个子节点,那么原本指向它的节点久得做些调整,使其指向它的子节点。最后,如果待删除节点包含两个子节点,正确的做法有两种:要么查找待删除节点左子树上的最大值,要么查找其右子树上的最小值。这里我们选择后一种方式。

顶点

function Vertex(label) {
this.label = label;
}

表示边

  • 邻接表
    在这里插入图片描述
  • 邻接矩阵

构建图

function Graph(v) {
this.vertices = v;
this.edges = 0;
this.adj = [];
for (var i = 0; i < this.vertices; ++i) {
this.adj[i] = [];
this.adj[i].push("");
}
this.addEdge = addEdge;
this.showGraph = showGraph;
this.dfs = dfs;
this.marked = [];
for (var i = 0; i < this.vertices; ++i) {
this.marked[i] = false;
}
}
function addEdge(v, w) {
this.ajd[v].push(w);
this.adj[w].push(v);
this.edges++;
}

function showGraph() {
for (var i = 0; i < this.vertices; ++i) {
putstr(i + "->");
for (var j = 0; j < this.vertices; ++j) {
if (this.adj[i][j] != undefined)
putstr(this.adj[i][j] + ' ');
}
print();
}
}

搜索图
深度优先搜索

function dfs(v) {
    this.marked[v] = true;
    // 用于输出的 if 语句在这里不是必须的
    if (this.adj[v] != undefined)
        print("Visited vertex: " + v);
    for each(var w in this.adj[v]) {
        if (!this.marked[w]) {
            this.dfs(w);
        }
    }
}

广度优先搜索

function bfs(s) {
    var queue = [];
    this.marked[s] = true;
    queue.push(s); // 添加到队尾
    while (queue.length > 0) {
        var v = queue.shift(); // 从队首移除
        if (v == undefined) {
            print("Visisted vertex: " + v);
        }
        for each(var w in this.adj[v]) {
            if (!this.marked[w]) {
                this.edgeTo[w] = v;
                this.marked[w] = true;
                queue.push(w);
            }
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值