前言
總括: 本文講解了數據結構中的[集合]概念,並使用javascript實現了集合。
- 原文博客地址:學習javascript數據結構(三)——集合
- 知乎專欄&&簡書專題:前端進擊者(知乎)&&前端進擊者(簡書)
- 博主博客地址:Damonare的個人博客
人生多風雨,何處無險阻。
正文
集合簡介
在上一篇學習javascript數據結構(二)——鏈表中我們說了鏈表這種數據結構,但歸根結底,不論是棧,隊列亦或是鏈表都是線性結構。他們都是一種很規矩的數據結構,就像幼兒園的小朋友排隊乖乖的站在那不會動一樣。
然而紛雜的數據並不會總是排隊站在那里,幼兒園小朋友一旦下了課那可就撒歡了,亂糟糟一團。可我們的幼兒園老師卻能分辨出這些小朋友,因為啥?因為每個小朋友都在一個班里,而且每一個小朋友都有自己的名字。老師自然很容易就找到小朋友了。
而本篇博文要說的集合正是一堆亂糟糟的數據
,唯一的共同點是這些數據隸屬於同一個集合
,看下百科給出的解釋:
由一個或多個元素所構成的叫做集合。
此處的元素就是小朋友了,他們所在的集合就是他們的班級。其實我們在高中的時候也接觸過集合的概念。那時候還沒有套路這個名詞,單純的歲月,那個年代對於集合是這么解釋的:
集合是指具有某種特定性質的具體的或抽象的對象匯總成的集體,這些對象稱為該集合的元素。
然后又是這么分類的:
- 空集:{}
- 有限集:{a,b,4}
- 無限集:{1,2,3,4...}
不過,數據結構中集合是沒有無限集這個概念的。再然后那時候的集合還有這么幾個特性:
- 確定性:給定一個集合,任給一個元素,該元素或者屬於或者不屬於該集合,二者必居其一,不允許有模棱兩可的情況出現。
- 互異性:一個集合中,任何兩個元素都認為是不相同的,即每個元素只能出現一次。有時需要對同一元素出現多次的情形進行刻畫,可以使用多重集,其中的元素允許出現多次。
- 無序性:一個集合中,每個元素的地位都是相同的,元素之間是無序的。集合上可以定義序關系,定義了序關系后,元素之間就可以按照序關系排序。但就集合本身的特性而言,元素之間沒有必然的序。
想當年哥還是個數學學霸,如今卻淪落為了一個碼農......真是讓人唏噓啊。咳咳!接着說:
集合還有這幾種常見的基本操作:
- 並集
- 交集
- 差集
而且我們數據結構中的集合基本是也符合高中時候的數學中的概念的。接下來我們是用ES5來實現集合,為啥子這么說呢......因為在ES6中已經新給出了Set,Map等幾個集合類,更加方便快捷的鎖定鍵值對。
集合的創建
首先我們先聲明一個集合類:
function(){
var items={};
}
接下來,我們需要給鏈表聲明一些方法:
- add(value):向集合添加一個新的項
- remove(value):從集合移除一個值
- has(value):如果值在集合中,返回true,否則返回false
- clear():移除集合中的所有項
- size():返回集合所包含的元素數量,與數組的length屬性相似
- values():返回一個集合中所有值的數組
- union(setName):並集,返回包含兩個集合所有元素的新集合(元素不重復)
- intersection(setName):交集,返回包含兩個集合中共有的元素的集合、
- difference(setName):差集,返回包含所有存在本集合而不存在setName集合的元素的新集合
- subset(setName):子集,驗證setName是否是本集合的子集
下面是Set類的完整代碼:
function Set() {
let items = {};
this.add = function(value){
if (!this.has(value)){
items[value] = value;
return true;
}
return false;
};
this.delete = function(value){
if (this.has(value)){
delete items[value];
return true;
}
return false;
};
this.has = function(value){
return items.hasOwnProperty(value);
//return value in items;
};
this.clear = function(){
items = {};
};
/**
* Modern browsers function
* IE9+, FF4+, Chrome5+, Opera12+, Safari5+
* @returns {Number}
*/
this.size = function(){
return Object.keys(items).length;
};
/**
* cross browser compatibility - legacy browsers
* for modern browsers use size function
* @returns {number}
*/
this.sizeLegacy = function(){
let count = 0;
for(let key in items) {
if(items.hasOwnProperty(key))
++count;
}
return count;
};
/**
* Modern browsers function
* IE9+, FF4+, Chrome5+, Opera12+, Safari5+
* @returns {Array}
*/
this.values = function(){
let values = [];
for (let i=0, keys=Object.keys(items); i<keys.length; i++) {
values.push(items[keys[i]]);
}
return values;
};
this.valuesLegacy = function(){
let values = [];
for(let key in items) {
if(items.hasOwnProperty(key)) {
values.push(items[key]);
}
}
return values;
};
this.getItems = function(){
return items;
};
this.union = function(otherSet){
let unionSet = new Set();
let values = this.values();
for (let i=0; i<values.length; i++){
unionSet.add(values[i]);
}
values = otherSet.values();
for (let i=0; i<values.length; i++){
unionSet.add(values[i]);
}
return unionSet;
};
this.intersection = function(otherSet){
let intersectionSet = new Set();
let values = this.values();
for (let i=0; i<values.length; i++){
if (otherSet.has(values[i])){
intersectionSet.add(values[i]);
}
}
return intersectionSet;
};
this.difference = function(otherSet){
let differenceSet = new Set();
let values = this.values();
for (let i=0; i<values.length; i++){
if (!otherSet.has(values[i])){
differenceSet.add(values[i]);
}
}
return differenceSet;
};
this.subset = function(otherSet){
if (this.size() > otherSet.size()){
return false;
} else {
let values = this.values();
for (let i=0; i<values.length; i++){
if (!otherSet.has(values[i])){
return false;
}
}
return true;
}
};
}
下面是ES6版本代碼:
let Set2 = (function () {
const items = new WeakMap();
class Set2 {
constructor () {
items.set(this, {});
}
add(value){
if (!this.has(value)){
let items_ = items.get(this);
items_[value] = value;
return true;
}
return false;
}
delete(value){
if (this.has(value)){
let items_ = items.get(this);
delete items_[value];
return true;
}
return false;
}
has(value){
let items_ = items.get(this);
return items_.hasOwnProperty(value);
}
clear(){
items.set(this, {});
}
size(){
let items_ = items.get(this);
return Object.keys(items_).length;
}
values(){
let values = [];
let items_ = items.get(this);
for (let i=0, keys=Object.keys(items_); i<keys.length; i++) {
values.push(items_[keys[i]]);
}
return values;
}
getItems(){
return items.get(this);
}
union(otherSet){
let unionSet = new Set();
let values = this.values();
for (let i=0; i<values.length; i++){
unionSet.add(values[i]);
}
values = otherSet.values();
for (let i=0; i<values.length; i++){
unionSet.add(values[i]);
}
return unionSet;
}
intersection(otherSet){
let intersectionSet = new Set();
let values = this.values();
for (let i=0; i<values.length; i++){
if (otherSet.has(values[i])){
intersectionSet.add(values[i]);
}
}
return intersectionSet;
}
difference(otherSet){
let differenceSet = new Set();
let values = this.values();
for (let i=0; i<values.length; i++){
if (!otherSet.has(values[i])){
differenceSet.add(values[i]);
}
}
return differenceSet;
};
subset(otherSet){
if (this.size() > otherSet.size()){
return false;
} else {
let values = this.values();
for (let i=0; i<values.length; i++){
if (!otherSet.has(values[i])){
return false;
}
}
return true;
}
};
}
return Set2;
})();
后記
集合是一種比較常見的數據結構,在JS中我們已經有了一種類似哈希表的東西:Object(對象)。但現在我們所說的集合只是以[value,value]形式存儲數據,下一節我們使用[鍵,值]形式存儲數據,和本文集合的實現略有不同。敬請期待:[學習javascript數據結構(四)——散列表]