Appearance
数据结构
什么是数据结构
- 在计算机科学中,数据结构(data structure)是计算机存储、组织数据的方式。
- 数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。
数据结构概念定义
- 数据:是用来描述一种客观事物的符号,分为数据元素、数据对象、数据项等。
- 结构:数据元素相互之间的关系,分为逻辑结构和存储结构两大类。
- 数据逻辑结构:指数据元素之间的前后件关系,分为集合、线性结构、非线性结构等。
- 数据存储结构:指数据的逻辑结构在计算机存储空间的存放形式,分为顺序结构、链式结构、索引结构、散列结构等。
数据结构有哪些
- 列表:
一个存储元素的线性集合(collection),元素可以通过索引来任意存取,索引通常是数字,用来计算元素之间存储位置的偏移量。
javascript
function List() {
this.listSize = 0;
this.pos = 0;
this.dataStore = [];
this.append = append;
this.remove = remove;
this.find = find;
this.length = length;
this.toString = toString;
this.insert = insert;
this.clear = clear;
this.contains = contains;
this.front = front;
this.end = end;
this.prev = prev;
this.next = next;
this.currPos = currPos;
this.moveTo = moveTo;
this.getElement = getElement;
this.hasNext = hasNext;
this.hasPrev = hasPrev;
}
function append(element) {
this.dataStore[this.listSize++] = element;
}
function find(element) {
for (var i = 0; i < this.dataStore.length; ++i) {
if (this.dataStore[i] == element) {
return i;
}
}
return -1;
}
function length() {
return this.listSize;
}
function toString() {
return this.dataStore;
}
function remove(element) {
var foundAt = this.find(element);
if (foundAt > -1) {
this.dataStore.splice(foundAt,1);
--this.listSize;
return true;
}
return false;
}
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(element) {
for (var 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];
}
function hasNext() {
return this.pos < this.listSize;
}
function hasPrev() {
return this.pos > 0;
}
// 测试
var names = new List();
names.append("Cynthia");
names.append("Raymond");
names.insert("Barbara", "Cynthia");
console.log(names.toString());
names.remove("Raymond");
console.log(names.toString());
for (names.front(); names.hasNext(); names.next()) {
console.log(names.getElement());
}
- 队列:
用于存储按顺序排列的数据,先进先出。
javascript
// 队列
function Queue() {
this.dataStore = [];
this.enqueue = enqueue; // 入队
this.dequeue = dequeue; // 出队
this.front = front;
this.back = back;
this.toString = toString;
this.empty = empty;
}
function enqueue(element) {
this.dataStore.push(element);
}
function dequeue() {
return this.dataStore.shift();
}
function front() {
return this.dataStore[0];
}
function back() {
return this.dataStore[this.dataStore.length - 1];
}
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;
}
}
// 测试
var q = new Queue();
q.enqueue("Cynthia");
q.enqueue("Raymond");
q.enqueue("Barbara");
console.log(q.toString());
q.dequeue();
console.log(q.toString());
console.log("Front of queue:" + q.front());
console.log("Back of queue:" + q.back());
// 实例
// 使用队列:方块舞的舞伴分配问题
// 使用队列对数据进行排序
// 优先队列
- 栈:
一种高效的数据结构,数据只能在栈顶添加或删除,先进后出。
javascript
// 栈
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;
}
// 测试
var s = new Stack();
s.push("Cynthia");
s.push("Raymond");
s.push("Barbara");
console.log("length:" + s.length());
console.log(s.peek());
var poped = s.pop();
console.log("The poped element is: " + poped);
console.log(s.peek());
s.clear();
console.log("length:" + s.length());
// 实例
// 进制间相互转换
// 回文判断
// 递归演示
// 堆和栈不一样
- 链表:
由一组节点组成的集合,每个节点都使用一个对象的引用指向它的后继。
javascript
// 节点
function Node(element) {
this.element = element;
this.next = null;
}
// 链表
function LinkedList() {
this.head = new Node("head");
this.find = find;
this.insert = insert;
this.remove = remove;
this.display = display;
this.findPrevious = findPrevious;
}
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;
}
function display() {
var currNode = this.head;
while (!(currNode.next == null)) {
console.log(currNode.next.element);
currNode = currNode.next;
}
}
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;
}
// test
var cities = new LinkedList();
cities.insert("Conway", "head");
cities.insert("Russellville", "Conway");
cities.insert("Carlisle", "Russellville");
cities.insert("Alma", "Carlisle");
cities.display();
cities.remove("Carlisle");
cities.display();
// 更多实例
// 双向链表
// 循环链表
- 字典:
以键-值对形式存储数据的数据结构。
javascript
// 字典
function Dictionary() {
this.add = add;
this.datastore = new Array();
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() {
for (var key in Object.keys(this.datastore).sort()) {
console.log(key + " -> " + this.datastore[key]);
}
}
function count() {
var n = 0;
for (var key in Object.keys(this.datastore)) {
++n;
}
return n;
}
function clear() {
for (var key in Object.keys(this.datastore)) {
delete this.datastore[key];
}
}
// 测试
var pbook = new Dictionary();
pbook.add("Raymond", "123");
pbook.add("David", "345");
pbook.add("Cynthia", "456");
console.log("Number of entries:" + pbook.count());
console.log("David is extension:" + pbook.find("David"));
pbook.showAll();
pbook.clear();
console.log("Number of entries:" + pbook.count());
- 散列表:
散列是一种常用的数据存储技术,散列后的数据可以快速地插入或取用。
javascript
// 散列表
function HashTable() {
this.table = new Array(137);
this.simpleHash = simpleHash;
this.betterHash = betterHash;
this.showDistro = showDistro;
this.put = put;
this.get = get;
}
// put for linear probing
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;
}
}
// put for separate chaining
function put(key, data) {
var pos = this.betterHash(key);
var index = 0;
if (this.table[pos][index] == undefined) {
this.table[pos][index] = data;
} else {
while (this.table[pos][index] != undefined) {
++index;
}
this.table[pos][index] = data;
}
}
function simpleHash(data) {
var total = 0;
for (var i = 0; i < data.length; ++i) {
total += data.charCodeAt(i);
}
console.log("Hash value: " + data + " -> " + total);
return total % this.table.length;
}
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 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 getRandomInt (min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function genStuData(arr) {
for (var i = 0; i < arr.length; ++i) {
var num = "";
for (var j = 1; j <= 9; ++j) {
num += Math.floor(Math.random() * 10);
}
num += getRandomInt(50,100);
arr[i] = num;
}
}
function buildChains(arr) {
for (var i = 0; i < arr.length; ++i) {
arr[i] = new Array();
}
}
function inHash(key, arr) {
var hash = simpleHash(key, arr);
var n = 0;
if (key == arr[hash][n]) {
return true;
} else {
while (arr[hash][n] != undefined) {
if (arr[hash][n] == key) {
return true;
}
++n;
}
}
return false;
}
// get for separate chaining
function get(key) {
var index = 0;
var hash = this.betterHash(key);
if (this.table[pos][index] = key) {
return this.table[pos][index+1];
} else {
while (this.table[pos][index] != key) {
index += 2;
}
return this.table[pos][index+1];
}
return undefined;
}
// get for linear probing
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;
}
function get(key) {
return this.table[this.betterHash(key)];
}
// 测试
var someNames = ["David", "Jennifer", "Donnie", "Raymond",
"Cynthia", "Mike", "Clayton", "Danny", "Jonathan"];
var hTable = new HashTable();
for (var i = 0; i < someNames.length; ++i) {
hTable.put(someNames[i]);
}
hTable.showDistro();
// 实例
// 解决碰撞的两种方法:
// 开链法
// 线性探测法
- 集合:
一种包含不同元素的数据结构。集合中的成员是无序的,集合中不允许相同成员存在。
javascript
// 集合
function Set() {
this.dataStore = [];
this.add = add;
this.remove = remove;
this.size = size;
this.union = union;
this.contains = contains;
this.intersect = intersect;
this.subset = subset;
this.difference = difference;
this.show = show;
}
function add(data) {
if (this.dataStore.indexOf(data) < 0) {
this.dataStore.push(data);
return true;
} else {
return false;
}
}
function remove(data) {
var pos = this.dataStore.indexOf(data);
if (pos > -1) {
this.dataStore.splice(pos,1);
return true;
} else {
return false;
}
}
function size() {
return this.dataStore.length;
}
function show() {
return "[" + this.dataStore + "]";
}
function contains(data) {
if (this.dataStore.indexOf(data) > -1) {
return true;
} else {
return false;
}
}
function union(set) {
var tempSet = new Set();
for (var i = 0; i < this.dataStore.length; ++i) {
tempSet.add(this.dataStore[i]);
}
for (var i = 0; i < set.dataStore.length; ++i) {
if (!tempSet.contains(set.dataStore[i])) {
tempSet.dataStore.push(set.dataStore[i]);
}
}
return tempSet;
}
function intersect(set) {
var tempSet = new Set();
for (var i = 0; i < this.dataStore.length; ++i) {
if (set.contains(this.dataStore[i])) {
tempSet.add(this.dataStore[i]);
}
}
return tempSet;
}
function subset(set) {
if (this.size() > set.size()) {
return false;
} else {
for (var member in this.dataStore) {
if (!set.contains(member)) {
return false;
}
}
}
return true;
}
function difference(set) {
var tempSet = new Set();
for (var i = 0; i < this.dataStore.length; ++i) {
if (!set.contains(this.dataStore[i])) {
tempSet.add(this.dataStore[i]);
}
}
return tempSet;
}
// 测试
var cis = new Set();
var it = new Set();
cis.add("Clayton");
cis.add("Jennifer");
cis.add("Danny");
it.add("Bryan");
it.add("Clayton");
it.add("Jennifer");
var diff = new Set();
diff = cis.difference(it);
console.log(cis.show() + " difference " + it.show() + " -> " + diff.show());
- 树:
一种非线性的数据结构,以分层的方式存储数据,被用来存储具有层级关系的数据。
javascript
// 节点
function Node(data, left, right) {
this.data = data;
this.count = 1;
this.left = left;
this.right = right;
this.show = show;
this.getmin = getmin;
this.getmax = getmax;
this.find = find;
}
function show() {
return this.data;
}
// 二叉树
function BST() {
this.root = null;
this.insert = insert;
this.inOrder = inOrder;
this.preOrder = preOrder;
this.postOrder = postOrder;
this.getmin = getmin;
this.getmax = getmax;
this.find = find;
this.remove = remove;
this.removeNode = removeNode;
this.getSmallest = getSmallest;
}
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.show() + " ");
inOrder(node.right);
}
}
// 先序遍历
function preOrder(node) {
if (!(node == null)) {
console.log(node.show() + " ");
preOrder(node.left);
preOrder(node.right);
}
}
// 后序遍历
function postOrder(node) {
if (!(node == null)) {
postOrder(node.left);
postOrder(node.right);
console.log(node.show() + " ");
}
}
function getmin() {
var current = this.root;
while (!(current.left == null)) {
current = current.left;
}
return current.data;
}
function getmax() {
var current = this.root;
while (!(current.right == null)) {
current = current.right;
}
return current.data;
}
function find(data) {
var current = this.root;
while (current.data != data) {
if (data < current.data) {
current = current.left;
} else {
current = current.right;
}
if (current == null) {
return null;
}
}
return current;
}
function getSmallest(node) {
if (node.left == null) {
return node;
} else {
return getSmallest(node.left);
}
}
function remove(data) {
root = removeNode(this.root, data);
}
function removeNode(node, data) {
if (node == null) {
return null;
}
if (data == node.data) {
// node has no children
if (node.left == null && node.right == null) {
return null;
}
// node has no left child
if (node.left == null) {
return node.right;
}
// node has no right child
if (node.right == null) {
return node.left;
}
// node has two children
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;
}
}
function prArray(arr) {
console.log(arr[0].toString + ' ');
for (var i = 1; i < arr.length; ++i) {
console.log(arr[i].toString() + ' ');
if ( i % 10 == 0) {
console.log("\n");
}
}
}
// 测试
var nums = new BST();
nums.insert(23);
nums.insert(45);
nums.insert(16);
nums.insert(37);
nums.insert(3);
nums.insert(99);
nums.insert(22);
console.log("Inorder traversal: ");
inOrder(nums.root);
console.log("\n");
console.log("Preorder traversal: ");
preOrder(nums.root);
console.log("\n");
console.log("Postorder traversal: ");
postOrder(nums.root);
console.log("\n");
var min = nums.getmin();
console.log("The minimum value of the BST is: " + min);
var max = nums.getmax();
console.log("The maximum value of the BST is: " + max);
inOrder(nums.root);
console.log("\n");
// console.log("Enter a value to search for: ");
// var value = parseInt(readline());
// var found = nums.find(value);
// if (found != null) {
// console.log("Found " + value + " in the BST.");
// } else {
// console.log(value + " was not found in the BST.");
// }
// inOrder(nums.root);
// console.log("\n");
// var num = parseInt(readline());
// nums.remove(num);
// inOrder(nums.root);
- 图:
由边的集合及顶点的集合组成。
javascript
// 图
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.bfs = bfs;
this.marked = [];
for (var i = 0; i < this.vertices; ++i) {
this.marked[i] = false;
}
}
function addEdge(v,w) {
this.adj[v].push(w);
this.adj[w].push(v);
this.edges++;
}
function showGraph() {
for (var i = 0; i < this.vertices; ++i) {
console.log(i + " -> ");
for (var j = 0; j
< this.vertices; ++j) {
if (this.adj[i][j] != undefined)
console.log(this.adj[i][j] + ' ');
}
console.log();
}
}
// 深度优先搜索
function dfs(v) {
this.marked[v] = true;
if (this.adj[v] != undefined) {
console.log("Visited vertex: " + v);
}
for (var w in this.adj[v]) {
if (!this.marked[w]) {
this.dfs(w);
}
}
}
// 广度优先搜索
function bfs(v) {
var queue = [];
this.marked[s] = true;
queue.push(s); // 添加到队尾
while (queue.length > 0) {
var v = queue.shift(); // 从队首移除
if (this.adj[v] != undefined) {
console.log("visited vertex: " + v);
}
for (var w in this.adj[v]) {
if (!this.marked[w]) {
this.marked[w] = true;
queue.push(w);
}
}
}
}
// 测试
g = new Graph(5);
g.addEdge(0,1);
g.addEdge(0,2);
g.addEdge(1,3);
g.addEdge(2,4);
g.showGraph();
// test dfs
g.dfs(0);
// test bfs
g.bfs(0);
- 上面对常用的9种数据结构做了一个简要的介绍。更好的理解数据结构,还是看图解、看示例源码比较好。