数据结构与算法JavaScript描述学习笔记

 

第2章 数组

2.1 创建数组

方式一:通过[ ]操作符声明一个数组变量(推荐使用):

var numbers = [];//数组长度为0
var numbers = [1,2,3,4,5];
console.log(numbers.length);//数组长度为5

方式二:可以调用Array的构造函数创建数组:

var numbers = new Array();
var numbers = new Array(1,2,3,4,5);//数组长度为5
//在调用Array的构造函数时,可以只传入一个参数,用来指定数组的长度。
var numbers = new Array(10);//数组长度为10

在脚本语言里很常见一个特性是,数组中的元素不必是同一个数据类型。

var objects = [1,"joe",true,null];

可以通过Array.isArray()来判断一个对象是否是数组。

var numbers = 3;
var arr = [1,2,3,4,5];
console.log(Array.isArray(numbers));//false
console.log(Array.isArray(arr));//true

2.2 读写数组

使用[ ]操作符:

var nums = [];
for(var i=0;i<100;i++){
    nums[i] = i+1; 
}

var nums = [1,2,3,4,5];
var sum = 0;
for(var i=0;i<nums.length;i++){
    sum+= nums[i];
}
console.log(sum);

由字符串生成数组:

var sentence = "the quick brown fox jumped over the lazy dog";
var words = sentence.split(" ");
for(var i=0;i<words.length;++i){
    console.log("word" + i + ":" + words[i]);
}

复制数组:

首先,可以将一个数组赋给另外一个数组。但是,简单的复制,只是为被复制的数组增加了一个新的引用。

当你通过原引用修改了数组的值,另外一个引用也会感知到这个变化。这种行为被称为浅复制。新数组依然指向原来的数组。

var nums = [];
for(var i=0;i<100;++i){
    nums[i] = i+1;
}
var samenums = nums;
nums[0] = 400;
console.log(samenums[0]);//400

深复制:将原数组中的每一个元素都复制一份到新数组中。

function copy(arr1,arr2){
    for(var i=0;i<arr1.length;i++){
        arr2[i] = arr1[i];
    }
}

var nums = [];
for(var i=0;i<100;i++){
    nums[i] = i+1;
}
var samenums = [];
copy(nums,samenums);
nums[0] = 400;
console.log(samenums[0]); //1

2.3 存取函数

js提供一组用来访问数组元素的函数,叫做存取函数。

查找元素:indexOf()

用途:用来查找传进来的参数在目标数组中是否存在。如果数组中包含多个相同的元素,indexOf()函数总是返回第一个与参数相同的元素的索引。

返回值:如果目标数组包含该参数,就返回该元素在数组中中的索引;如果不包含,就返回-1

var names = ["David","Cynthia","Raymond","Clayton","Jennifer"];
var name = "joey";
var position = names.indexOf(name);
if(position !== -1){//或if(position >=0 )
    console.log("Found" + position);
}else{
    console.log("Not Found");
}

lastIndexOf():该函数返回相同元素中最后一个元素的索引。如果没有找到相同的元素,则返回-1.

var names = ["David","Cynthia","Mike","Raymond","Clayton","Jennifer","Mike"];
var name = "Mike";
console.log(names.indexOf(name));//2
console.log(names.lastIndexOf(name));//6

数组的字符串表示:join() 和 toString()

这两个方法都返回一个包含数组所有元素的字符串,各元素之间用逗号分隔。

var names = ["David","Cynthia","Mike","Raymond","Clayton","Jennifer","Mike"];
var namesstr = names.join();
console.log(namesstr);//David,Cynthia,Mike,Raymond,Clayton,Jennifer,Mike
var namesstr = names.toString();
console.log(namesstr);//David,Cynthia,Mike,Raymond,Clayton,Jennifer,Mike

由已有数组创建新数组:concat()和splice()

concat():可以合并多个数组创建一个新数组。

splice():截取一个数组的子集创建一个新数组。

var cisDept = ["David","Cynthia","Mike","Raymond","Clayton","Jennifer","Mike"];
var dmpDept = ["Danny","Bryan","Terrill"];
var itDiv = cisDept.concat(dmpDept);
console.log(itDiv);//["David", "Cynthia", "Mike", "Raymond", "Clayton", "Jennifer", "Mike", "Danny", "Bryan", "Terrill"]

splice():该方法的第一个参数是截取的起始索引,第二个参数是截取的长度。

var cisDept = ["David","Cynthia","Mike","Raymond","Clayton","Jennifer","Mike"];
var dmpDept = cisDept.splice(3,3);
console.log(dmpDept);// ["Raymond", "Clayton", "Jennifer"]

2.4 可变函数

为数组添加元素:push()和unshift()

 

 

 

 

 

 

 

第3章 列表

3.1 列表的抽象数据类型定义

listSize(属性)列表的元素个数
pos(属性)列表的当前位置
length(属性)返回列表中元素的个数
clear()(方法)

清空列表中的所有元素

toString()(方法)返回列表的字符串行式
getElement()(方法)返回当前位置的元素
insert()(方法)在现有元素后插入新元素
append()(方法)在列表的末尾添加新元素
remove()(方法)在列表中删除元素
front()(方法)将列表的当前位置移动到第一个元素
end()(方法)将列表的当前位置移动到最后一个元素
pre()(方法)将当前位置后移一位
next()(方法)将当前位置前移一位
currPos()(方法)返回列表的当前位置
moveTo()(方法)将当前位置移动到指定位置

3.2  实现列表类

 

function List(){
    this.listSize = 0;
    this.pos = 0;
    this.dataStore = [];//初始化一个空数组来保存列表元素
    this.clear = clear;
    this.find = find;
    this.toString = toString;
    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;
}

append:给列表添加源:

function append(element){
    this.dataStore[this.listSize++] = element;
}

remove:从列表中删除元素:首先需要在列表中找到该元素,然后删除它。

find()方法用查找要删除的元素:

function find(element){
    for(var i=0;i<this.dataStore.length;++i){
        if(this.dataStore[i] == element){
            return i;
        }
    }
    return -1;
}

 find() 方法通过对数组对象dataStore 进行迭代,查找给定的元素。如果找到,就返回该元素在列表中的位置,否则返回-1,这是在数组中找不到指定元素时返回的标准值。我们可以在remove() 方法中利用此值做错误校验。
remove() 方法使用find() 方法返回的位置对数组dataStore 进行截取。数组改变后,将变量listSize 的值减1,以反映列表的最新长度。如果元素删除成功,该方法返回true,否则返回false

function remove(element){
    var foundAt = this.find(element);
    if(foundAt > -1){
        this.dataStore.splice(foundAt,1);
        --this.listSize;
        return true;
    }
    return false;
}

 

length:列表中有多少个元素

function length(){
    return this.listSize;
}

toString:显示列表中的元素

function toString(){
    return this.dataStore;
}

简单的测试:

var names = new List();
names.append("Cynthia1");
names.append("Cynthia2");
names.append("Cynthia3");
names.append("Cynthia4");
console.log(names.toString());//(4) ["Cynthia1", "Cynthia2", "Cynthia3", "Cynthia4"]
names.remove("Cynthia4");
console.log(names.toString());//(3) ["Cynthia1", "Cynthia2", "Cynthia3"]

insert:向列表中插入一个元素

insert() 方法用到了find() 方法,find() 方法会寻找传入的after 参数在列表中的位置,找到该位置后,使用splice() 方法将新元素插入该位置之后,然后将变量listSize 加1 并返回true,表明插入成功。

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

clear:清空列表中所有的元素

clear() 方法使用delete 操作符删除数组dataStore,接着在下一行创建一个空数组。最后一行将listSize 和pos 的值设为1,表明这是一个新的空列表。

function clear(){
    delete this.dataStore;
    this.dataStore = [];
    this.listSize = this.pos = 0;
}

contains:判断给定值是否在列表中

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 - 1){
        ++this.pos;
    }
}

function currPos(){
    return this.pos;
}

function moveTo(position){
    this.pos = position;
}

function getElement(){
    return this.dataStore[this.pos];
}

var names = new List();
names.append("Clayton1");
names.append("Clayton2");
names.append("Clayton3");
names.append("Clayton4");
names.append("Clayton5");
names.append("Clayton6");
names.append("Clayton7");
names.front();
console.log(names.getElement());//Clayton1
names.next();
console.log(names.getElement());//Clayton1

3.3 使用迭代器访问列表

使用迭代器,可以不必关心数据的内部存储方式,以实现对列表的遍历。前面提到的方法front()、end()、prev()、next() 和currPos 就实现了cList 类的一个迭代器。以下是和使用数组索引的方式相比,使用迭代器的一些优点。
•访问列表元素时不必关心底层的数据存储结构。
• 当为列表添加一个元素时,索引的值就不对了,此时只用更新列表,而不用更新迭代器。
• 可以用不同类型的数据存储方式实现cList 类,迭代器为访问列表里的元素提供了一种
统一的方式。

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

 

 

第4章 栈

4.1 栈的操作

栈:后人先出

push():入栈

pop():出栈

peek():只返回栈顶元素,而不删除它。

clear():清除栈内所有元素。

empty属性,length属性

4.2 栈的实现

//定义Stack类的构造函数
function Stack(){
    this.dataStore = [];
    this.top = 0;
    this.push = push;
    this.pop = pop;
    this.peek = peek;
    this.clear = clear;
    this.length = length;
}

//实现push()方法:向栈中压入一个新元素,需要将其保存在数组中变量top所对应的位置,top值加1
function push(element){
    this.dataStore[this.top++] = element;
}

//pop()方法:返回栈顶元素,同时将变量top的值减1
function pop(){
    return this.dataStore[--this.top];
}

//peek()方法:返回数组的第top-1个位置的元素,即栈顶元素
function peek(){
    return this.dataStore[this.top-1];
}

//length()方法:通过返回top值的方式返回栈内的元素个数
function length(){
    return this.top;
}

//clear()方法:将变量top的值设为0,清空一个栈
function clear(){
    this.top = 0;
}


//测试
var s = new Stack();
s.push("David1");
s.push("David2");
s.push("David3");
s.push("David4");
console.log(s.length());//4
var poped = s.pop();
console.log(poped);//Davidi4
console.log(s.peek());//Davidi3
s.push("Cynthia");
console.log(s.peek());//Cynthia
s.clear();
console.log(s.length());//0
console.log(s.peek());//undefined
s.push("Cynthia2");
console.log(s.peek());//Cynthia2

4.3 使用Stack类

4.3.1 数值间的相互转换

可以利用栈将一个数字从一种数制转换成另一种数制。假设将数字n转换为以b为基数的数字,转换思想如下:

  • 最高位为n % b,将此压入栈。
  • 使用n / b代替n.
  • 重复上两步,直到n等于0,且没有余数。
  • 持续将栈内元素弹出,直到栈为空,依次将这些元素排列。

将八进制转化为二进制

function mulBase(num,base){
    var s = new Stack();
    do{
        s.push(num % base);
        num = Math.floor(num /= base);
    }while(num>0);
    var converted = "";
    while(s.length() > 0){
            converted += s.pop();
        }
        return converted;
    }
   
var num = 32;
var base = 2;
var newNum = mulBase(num,base);
console.log(newNum);//100000

4.3.2 判断一个单词是否是回文

回文:一个单词、短语或是数字,从前往后和从后往前都是一样的。比如:"dad","racecar",1001等

思路:字符串完整压入栈内后,通过持续弹出栈中的每个字母就可以得到一个新字符串,该字符串刚好与原来的字符串顺序相反。比较两个字符串,如果两个字符串相等就是回文。

function isPlindrome(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(word == rword){
        return true;    
    }else{
        return false;
    }
}

var word = "abccba";
console.log(isPlindrome(word));//true

4.3.3 栈实现递归

//递归函数
function factorial(n){
    if(n === 0){
        return 1;
    }else{
        return n*factorial(n-1);
    }
}

//使用栈模拟递归过程
function fact(n){
    var s = new Stack();
    while(n>1){
        s.push(n--);
    }
    var product = 1;
    while(s.length() > 0){
        product *= s.pop();
    }
    return product;
}
console.log(factorial(5));//120
console.log(fact(5));//120

第五章 队列

5.1 队列的操作

队列:先进先出

入队:向队列中插入新元素

出队:删除操作

5.2 一个用数组实现的队列

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

//front()方法:读取队首的元素
function front() {
return this.dataStore[0];
}

//back()方法:读取队尾的元素
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;
}

//empty()方法:判断队列是否为空
function empty() {
if (this.dataStore.length == 0) {
return true;
}
else {
return false;
}
}
//测试
var q = new Queue();
q.enqueue("Meredith");
q.enqueue("Cynthia");
q.enqueue("Jennifer");
console.log(q.toString());//Meredith  Cynthia  Jennifer
q.dequeue();
console.log(q.toString());//Cynthia  Jennifer
console.log("Front of queue: " + q.front());//Front of queue: Cynthia
console.log("Back of queue: " + q.back());//Back of queue: Jennifer

5.3 使用队列: 方块舞伴分配问题

 

 

第6章 链表

6.1 设计一个基于对象的链表

//使用构造函数来创建节点
function Node(element){
    this.element = element;
    this.next = null;
}
//LinkedList类
function LList(){
    this.head = new Node("head");
    this.find = find;
    this.insert = insert;
    this.remove = remove;
    this.display = display;
}

插入新节点

首先要明确在哪个节点前面或者后面插入一个新的节点。在一个已知节点后面插入元素时,先要找到“后面”的节点。为此,创建一个辅助方法find(),该方法遍历链表,查找给定数据。如果找到数据,该方法就返回保存该数据的节
点。find() 方法的实现代码如下所示:

function find(item){
    var currNode = this.head;
    while(currNode.element != item){
        currNode = currNode.next;
    }
    return currNode;
}

//insert()
function insert(newElement,item){
    var newNode = new Node(newElement);
    var current = this.find(item);
    newNode.next = current.next;
    current.next = newNode; 
}

//display():显示链表中的元素
function display(){
    var currNode = this.head;
    while(!(currNode.next == null)){
        console.log(currNode.next.element);
        currNode = currNode.next;
    }
}

 

 

第10章 二叉树和二叉查找树

10.1 实现二叉查找树

Node类的定义:

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

BST 先要有一个insert() 方法,用来向树中加入新节点。这个方法有点复杂,需要着重讲解。首先要创建一个Node 对象,将数据传入该对象保存。其次检查BST 是否有根节点,如果没有,那么这是棵新树,该节点就是根节点,这个方法到此也就完成了;否则,进入下一步。
如果待插入节点不是根节点,那么就需要准备遍历BST,找到插入的适当位置。该过程类似于遍历链表。用一个变量存储当前节点,一层层地遍历BST。进入BST 以后,下一步就要决定将节点放在哪个地方。找到正确的插入点时,会跳出循环。查找正确插入点的算法如下。
(1) 设根节点为当前节点。
(2) 如果待插入节点保存的数据小于当前节点,则设新的当前节点为原节点的左节点;反
之,执行第4 步。
(3) 如果当前节点的左节点为null,就将新的节点插入这个位置,退出循环;反之,继续
执行下一次循环。
(4) 设新的当前节点为原节点的右节点。
(5) 如果当前节点的右节点为null,就将新的节点插入这个位置,退出循环;反之,继续
执行下一次循环。

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

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值