链表
链表和数组一样,可以用来存储一系列的元素,但是链表和数组的实现机制完全不同
链表中的元素在内存中不必是连续的空间
链表的每一个元素由一个存储元素本身的节点和一个指向下一个元素的引用(指针、连接)组成
相对于数组,链表有一些优势:
- 内存空间不是必须连续的,可以充分利用计算机的内存,实现灵活的内存动态管理
- 链表不必在创建的时候就确定大小,并且大小可以无限的延伸下去
- 链表在插入和删除数据时,时间复杂度可以达到O(1),相对数组效率就高很多
相对于数组,链表有一些缺点:
- 链表访问任何一个位置的元素是,都需要从头开始访问(无法跳过第一个元素访问任何一个元素)
- 无法通过下标直接访问元素,需要从头一个个访问,直到找到对应的元素
链表的操作
<1> append(element):向列表尾部添加一个新的项
<2> insert(position,element):向列表的特定位置插入一个新的项
<3> get(position):获取对应位置的元素
<4> indexOf(element):返回元素在列表中的索引,如果列表中没有该元素则返回-1
<5> update(position,element):修改某个位置的元素
<6> removeAt(position):从列表的特定位置移除一项
<7> remove(element):从列表中移除一项
<8> isEmpty():如果链表中不包含任何元素,返回true,如果链表长度大于0则返回false
<9> size():返回链表中包含的元素个数,与数组的length属性类似
<10> toString():由于列表项使用了Node类,就需要重写继承自JavaScript对象默认的toString方法。让其只输出元素的值
封装链表结构
1、toString方法的实现
由于列表项使用了Node类,就需要重写继承自JavaScript对象默认的toString方法。让其只输出元素的值
//封装链表类 function LinkedList() { //内部类 function Node(data, next) { this.data = data; this.next = null; } //属性 this.head = null; //记录链表的头指针 this.length = 0; //记录链表的长度//toString方法 LinkedList.prototype.toString = function () { //定义变量 var current=this.head var result = '' //循环获取一个个节点 while(current){ result += current.data + " " //指针向后移动 current = current.next } return result } }
2、append方法的实现
向列表尾部添加一个新的项
//封装链表类 function LinkedList() { //内部类 function Node(data, next) { this.data = data; this.next = null; } this.head = null; //记录链表的头指针 this.length = 0; //记录链表的长度 //append方法 LinkedList.prototype.append = function (data) { // 1、创建新节点 var newNode = new Node(data); //2、判断添加的是否是第一个节点 if (this.length == 0) { //是第一个节点 //指针指向这个新节点 this.head = newNode } else { //3、如果不是第一个节点 //找到最后一个节点 var current = this.head; //判断下一个节点next是否为空,从而找到最后一个节点 while (current.next) { current = current.next } //最后一个节点的next指向新节点 current.next = newNode } //新添加节点之后把列表长度加一 this.length += 1 } }
测试:
//测试 var list = new LinkedList() list.append("a") list.append("b") list.append("c") alert(list)
3、insert方法的实现
向列表的特定位置插入一个新的项
//封装链表类 function LinkedList() { //内部类 function Node(data, next) { this.data = data; this.next = null; } this.head = null; //记录链表的头指针 this.length = 0; //记录链表的长度//insert方法 LinkedList.prototype.insert = function (position,data) { /* * 1、对position进行越界判断,位置为负数; * 长度的判断插入的位置大于链表的长度 * */ if(position < 0 || position > this.length) return false //2、根据data创建newNode var newNode = new Node(data) //3、判断插入的位置是否是第一个 if(position == 0) { newNode.next=this.head //当前节点指向head指向的节点 this.head=newNode //head指向当前节点 } else { //position的位置在链表的长度内 var index = 0 var current = this.head var previous = null while (index++ < position) { //找到了position需要插入的位置 previous = current current = current.next } newNode.next=current previous.next = newNode } //4、length加一 this.length += 1 return true } }
测试:
//测试 var list = new LinkedList() list.append("a") list.append("b") list.append("c") // alert(list) list.insert(0, 'aaa') list.insert(3, 'bbb') list.insert(5, 'ccc') alert(list)
4、get方法的实现
获取某个位置的元素
//封装链表类 function LinkedList() { //内部类 function Node(data, next) { this.data = data; this.next = null; } this.head = null; //记录链表的头指针 this.length = 0; //记录链表的长度//get方法 LinkedList.prototype.get = function (position) { //越界判断 if (position < 0 || position >= this.length) return null //获取对应的data var current = this.head var index = 0 while (index++ < position) { current = current.next } return current.data } }
测试:
//测试 var list = new LinkedList() list.append("a") list.append("b") list.append("c") // alert(list) list.insert(0, 'aaa') list.insert(3, 'bbb') list.insert(5, 'ccc') alert(list) alert(list.get(3))
5、indexOf方法的实现
返回元素在列表中的索引,如果列表中没有该元素则返回-1
//封装链表类 function LinkedList() { //内部类 function Node(data, next) { this.data = data; this.next = null; } this.head = null; //记录链表的头指针 this.length = 0; //记录链表的长度 //indexOf方法 LinkedList.prototype.indexOf = function (data) { //定义变量 var current = this.head var index = 0 //查找 while (current) { if (current.data == data) return index current = current.next index +=1 } //没有找到返回-1 return -1 } }
测试:
var list = new LinkedList() list.append("a") list.append("b") list.append("c") // alert(list) list.insert(1, 'aaa') list.insert(3, 'bbb') list.insert(5, 'ccc') alert(list) alert(list.indexOf('aaa')) alert(list.indexOf('ddd'))
6、update方法的实现
修改某个位置的元素
//封装链表类 function LinkedList() { //内部类 function Node(data, next) { this.data = data; this.next = null; } this.head = null; //记录链表的头指针 this.length = 0; //记录链表的长度//update方法 LinkedList.prototype.update = function (position,newData) { //越界判断 if(position < 0 || position >= this.length) return false //查找位置修改数据 var current=this.head var index=0 while(index++ < position){ current=current.next } //将position位置的data修改newData current.data=newData return true } }
测试:
var list = new LinkedList() list.append("a") list.append("b") list.append("c") // alert(list) list.insert(1, 'aaa') list.insert(3, 'bbb') list.insert(5, 'ccc') alert(list) alert(list.update(3,'ddd')) alert(list)
7、removeAt方法的实现
从列表的特定位置移除一项
//封装链表类 function LinkedList() { //内部类 function Node(data, next) { this.data = data; this.next = null; } this.head = null; //记录链表的头指针 this.length = 0; //记录链表的长度 LinkedList.prototype.removeAt = function (position) { //越界判断 if (position < 0 || position >= this.length) return null var current = this.head //判断删除的是否是第一个节点 if (position == 0) { this.head = this.head.next } else { var index = 0 var previous = null while (index++ < position) { previous = current current = current.next } //前一个节点的next指向curent的next previous.next = current.next } //长度减一5 this.length -= 1 return current.data } }
测试:
//测试 var list = new LinkedList() list.append("a") list.append("b") list.append("c") // alert(list) list.insert(1, 'aaa') list.insert(3, 'bbb') list.insert(5, 'ccc') alert(list) alert(list.removeAt(3)) alert(list)
8、removeAt方法的实现
从列表的特定位置移除一项
//封装链表类 function LinkedList() { //内部类 function Node(data, next) { this.data = data; this.next = null; } this.head = null; //记录链表的头指针 this.length = 0; //记录链表的长度//indexOf方法 LinkedList.prototype.indexOf = function (data) { //定义变量 var current = this.head var index = 0 //查找 while (current) { if (current.data == data) return index current = current.next index += 1 } //没有找到返回-1 return -1 }//removeAt方法 LinkedList.prototype.removeAt = function (position) { //越界判断 if (position < 0 || position >= this.length) return null var current = this.head //判断删除的是否是第一个节点 if (position == 0) { this.head = this.head.next } else { var index = 0 var previous = null while (index++ < position) { previous = current current = current.next } //前一个节点的next指向curent的next previous.next = current.next } //长度减一5 this.length -= 1 return current.data } //remove方法 LinkedList.prototype.remove = function (data) { //获取data在列表中的位置 var position = this.indexOf(data) //根据位置信息删除节点 return this.removeAt(position) } }
测试:
//测试 var list = new LinkedList() list.append("a") list.append("b") list.append("c") // alert(list) list.insert(1, 'aaa') list.insert(3, 'bbb') list.insert(5, 'ccc') alert(list) alert(list.remove('a')) alert(list)
9、isEmpty和size方法的实现
//封装链表类 function LinkedList() { //内部类 function Node(data, next) { this.data = data; this.next = null; } this.head = null; //记录链表的头指针 this.length = 0; //记录链表的长度 LinkedList.prototype.isEmpty=function () { return this.length == 0 } LinkedList.prototype.size=function () { return this.length } }
测试:
//测试 var list = new LinkedList() list.append("a") list.append("b") list.append("c") // alert(list) list.insert(1, 'aaa') list.insert(3, 'bbb') list.insert(5, 'ccc') alert(list) alert(list.isEmpty()) alert(list.size())