链表

发表于 2017-12-17 11:29:16 | 分类于 算法 |

链表的定义

​链表存储有序的元素集合,但不同于数组,链表中的元素在内存中并不是连续放置的。

​每个元素由一个存储元素本身的节点和一个指向下一个元素的引用(也称指针或链接)组成。

比较:链表、数组

  • 数组
    • 大多数语言中,数组的大小是固定的,从数组的起点或中间插入或移除项的成本很高,因为需要移动元素(JavaScirpt 的 Array 类方法可以帮助我们做这些事,但背后的情况同样是这样)。
    • 数组可以直接访问任何位置的元素。
  • 链表
    • 添加或移除元素的时候,不需要移动其他元素。
    • 访问链表中间的一个元素,需要从起点(表头)开始迭代链表,直到找到所需的元素。

链表的方法

append(element):向链表尾部添加一个新大的项。

insert(position, element):向链表特定位置插入一个新的项。

remove(element):从列表移除一项。

indexOf(element):返回元素在链表中的索引。如果没有该元素,则返回-1.

removeAt(position):从链表特定位置移除一项。

isEmpty():如果链表不包含任何元素,返回 true。如果链表长度大于 0 则返回 false。

size():返回链表包含的元素个数。

toString():输出链表包含的所有元素。

链表的创建

function LinkedList ( ) {
  	
  	// Node 辅助类
  	// 用来表示要加入列表的项
  	// 包含一个 element 属性,即要添加到列表的值
  	// 以及一个 next 属性,即指向列表中下一个节点项的指针
  	var Node = function ( element ) {
    	this.element = element ;
      	this.next = null ;
  	} ;
  	
  	// length ,存储列表项的数量
  	var length = 0 ;
  	// head,存储第一个节点的引用
  	var head = null ;
  	
  	// LinkedList 类的方法
  	this.append = function ( element ) {
      	
      	var node = new Node ( element ) ,
            current ;
      	
      	if ( head === null ) { 
        	head = node ; 
        }
      	else {
          	current = head ;
          
          	while ( current.next ) {
              	current = current.next ;
          	}
          	
          	current.next = node ;
      	}
      
      	length++ ;
  	} ;
  
  
  	this.insert = function ( position, element ) {
      	
      	if ( position >= 0 && position <= length ) {
          	
          	var node = new Node ( element );
            var	current = head;
            var previous;
        	var index = 0;
          	
          	if ( position === 0) {
              	node.next = current;
              	head = node;
            }
          	else {
              	while ( index < position ) {
                  	previous = current;
                  	current = current.next;
					index++;
              	}
              	node.next = current;
              	previous.next = node;
          	}

          	length++; 
          	return true;
      	}
      	else {
          	return fasle;
      	}
  	} ;
  
  
  	this.removeAt = function ( position ) {
      	
      	if ( position > -1 && position < length ) {
          	var current = head ,
                previous ,
                index = 0 ;
          	
          	if (position === 0 ) {
              	head = current.next ;
          	}
          	else {
              	while ( index < position ) {
                  	previous = current ;
                  	current = current.next;
					index++;
              	}
              
              	// 将 previous 与 current 的下一项链接起来:跳过 current ,从而移除它
              	previous.next = current.next ;
          	}
          
          	length--;
          	
          	return current.element ; 
      	}
      	else {
          	return null ;
      	}
  	} ;
  
  
  	this.indexOf = function ( element ) {
      	
      	var current = head;
        var index = -1;
      
      	while ( current ) {
          	if ( element === current.element ) {
              	return index;
          	}
          index++;
          current = current.next;
      	}
      	
      	return -1;
  	} ;
  
  	
  	this.remove = function ( element ) {
      	var index = this.indexOf ( element ) ;
       	return this.removeAt ( index ) ;
  	} ;
  
  	this.isEmpty = function ( ) {
      	return length === 0 ;
  	} ;
  
  
  	this.size = function ( ) {
      	return length ;
  	} ;
  
  
  	this.getHead = function ( ) {
      	return head ;
  	} ;
  
  
  	this.toString = function ( ) {
      	
      	var current = head ,
            string = "" ;
      	
      	while ( current ) {
          	string += current.element ;
          	current = current.next ;
      	}
      	
      	return string ;
  	} ;
  
}

双向链表

​普通链表,一个节点只有链向下一个节点的链接。

​双向链表,链接是双向的:一个链向下一个元素,另一个链像前一个元素。

双向链表的创建

funciton DoublyLinkedList ( ) {
   
	var Node = function ( element ) {
		this.element = element ;
		this.next = null ;
		// 新增的,用来保存前一项的引用。
		this.prev = null ; 
	};

	var length = 0 ;
	var head = null ;
	// 新增的,用来保存列表最后一项的引用
	var tail = null ; 
  
	this.insert = function ( position , element ) {  	
		// 检查越界值
		if ( position >= 0 && position <= length ) {
			
			var node = new Node ( element ) ,
				current = head ,
				previous ,
				index = 0;
			
			if ( position === 0) { // 在第一个位置添加
				
				if ( !head ) { // 新增的 
					head = node ;
					tail = node ;
				}
				else {
					node.next = current ;
					current.prev = node ; // 新增的
					head = node ;
				}
			}
			else if ( positon === length ) { //最后一项 //新增的
				current = tail ;
				current.next = node ;
				node.prev = current ;
				tail = node ;
			}
			else {
				while ( index < position ) {
					previous = current ;
					current = current.next ;
					index++;
				}
				node.next = current ;
				previous.next = node ;
				
				current.prev = node ; // 新增的
				node.prev = previous ; // 新增的
			}
				
			length++ ; // 更新列表长度
			return ture ;
		}
		else {
			return false ;
		}
	};
  
	this.removeAt = function ( position ) {
		//检查越界值
		if ( position > -1 && position < length ) {
			var current = head ,
				previous ,
				index = 0 ;
			
			// 移除第一项
			if( positon === 0 ) {
				
				head = curent.next ;
				
				// 如果只有一项,更新 tail 
				if ( length === 1 ) {
					tail = null ;
				}
				else {
					head.prev = null ;
				}
			}
			else if ( position === length - 1 ) { // 最后一项
				current = tail ;
				tail =current.prev ;
				tail.next = null ;
			}
			else {
				while ( index < position ) {
					previous = current ;
					current = current.next ;
					index++;
				}
				
				// 将 previous 与 current 的下一项链接起来,跳过 current
				previous.next = current,next ;
				current.next.prev = previous ;
			}
			
			length-- ;
			return current.element ;
				
		}
		else {
			return null ;
		}
	} ;
  
}

循环链表

​循环链表与链表之间的唯一区别在于,循环链表最后一个元素指向下一个元素的指针( tail.next ),是指向第一个元素(head),而不是引用 null。