链表和数组一样是一种数据结构。
数组是将元素在内存中连续存放,由于每个元素占用内存相同,所以可以通过下标迅速访问数组中任何元素。但是如果要在数组中增加一个元素,需要移动大量元素,在内存中空出一个元素的空间,然后将要增加的元素放在其中。同样的道理,如果想删除一个元素,同样需要移动大量元素去填掉被移动的元素。
链表恰好相反,链表中的元素在内存中不是顺序存储的,而是通过存在元素中的指针联系到一起。如:上一个元素有个指针指到下一个元素,以此类推,直到最后一个元素。如果要访问链表中一个元素,需要从第一个元素开始,一直找到需要的元素位置。但是增加和删除一个元素对于链表数据结构就非常简单了, 只要修改元素中的指针就可以了。
使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。
链表最明显的好处就是,常规数组排列关联项目的方式可能不同于这些数据项目在记忆体或磁盘上顺序,数据的存取往往要在不同的排列顺序中转换。而链表是一种自我指示数据类型,因为它包含指向另一个相同类型的数据的指针(链接)。
数组是将元素在内存中连续存放,由于每个元素占用内存相同,所以可以通过下标迅速访问数组中任何元素。但是如果要在数组中增加一个元素,需要移动大量元素,在内存中空出一个元素的空间,然后将要增加的元素放在其中。同样的道理,如果想删除一个元素,同样需要移动大量元素去填掉被移动的元素。
链表恰好相反,链表中的元素在内存中不是顺序存储的,而是通过存在元素中的指针联系到一起。如:上一个元素有个指针指到下一个元素,以此类推,直到最后一个元素。如果要访问链表中一个元素,需要从第一个元素开始,一直找到需要的元素位置。但是增加和删除一个元素对于链表数据结构就非常简单了, 只要修改元素中的指针就可以了。
使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。
链表最明显的好处就是,常规数组排列关联项目的方式可能不同于这些数据项目在记忆体或磁盘上顺序,数据的存取往往要在不同的排列顺序中转换。而链表是一种自我指示数据类型,因为它包含指向另一个相同类型的数据的指针(链接)。
从上面的比较可以看出,如果需要快速访问数据,很少或不插入和删除元素,就应该用数组;相反, 如果需要经常插入和删除元素就需要用链表数据结构了。
PHP实现的单链表,如下代码:
//结点类
class Node{
private $next = NULL; //下一个结点指针
private $data = NULL; //数据
public function Node($data, $next = NULL){
$this->data = $data;
$next && $this->next = $next;
}
public function getData(){
return $this->data;
}
public function setData($data){
$this->data = $data;
}
public function getNext(){
return $this->next;
}
public function setNext($next){
$this->next = $next;
}
}
//单链表类
class LinkList{
private $data_list = NULL; //结点集
public function LinkList($data = false){
$this->data_list = array();
$title = new Node(NULL);
$this->data_list[] = $title;
if($data){
if(is_array($data)){
$this->addMoreData($data);
}else{
$this->addData($data);
}
}
}
//返回第N个结点的值
public function getNodeByNumber($number){
return $this->data_list[$this->findKeyByNumber($number)]->getData();
}
//添加一组结点
public function addMoreData($datas){
foreach($datas as $value){
$this->addData($value);
}
}
//添加结点统一入口,供外面调用
//$number 添加在第几个结点的后面
public function addData($data, $number = false){
$node = new Node($data);
if($number === FALSE || $number == count($this->data_list)){
$this->insertLastNode($node);
}elseif($number > count($this->data_list)){
return false;
}else{
$this->insertNode($node, $number);
}
}
//插入一个结点到最后
private function insertLastNode($node){
$node->setNext(NULL);
$lastKey = $this->findLastNode();
$insert_key = $this->insertNodeIntoArray($node);
$this->data_list[$lastKey]->setNext($insert_key);
}
//插入一个结点
private function insertNode($node, $number){
$insert_number = $this->findKeyByNumber($number);
$node->setNext($this->data_list[$insert_number]->getNext());
$insert_key = $this->insertNodeIntoArray($node);
$this->data_list[$insert_number]->setNext($insert_key);
}
//查找第N个结点对应的数组key
private function findKeyByNumber($number){
$i = $key = 0;
while($i < $number){
$key = $this->data_list[$key]->getNext();
$i ++;
}
return $key;
}
//将结点加入数组
private function insertNodeIntoArray($node){
$this->data_list[] = $node;
return $this->getLastKey();
}
//删除结点
public function deleteNode($number){
if($number == 0 || $number > count($this->data_list)){
return false;
}
$pre_key = $this->findKeyByNumber($number - 1);
$key = $this->data_list[$pre_key]->getNext();
$this->data_list[$pre_key]->setNext($this->data_list[$key]->getNext());
unset($this->data_list[$key]);
}
//查找某结点的前一个结点
private function getPreNodeKey($key){
foreach($this->data_list as $k=>$v){
if($v->getNext() == $key){
return $k;
}
}
return false;
}
//打印链表
public function getData_list(){
return $this->data_list;
}
//返回数组的最后一个键
private function getLastKey(){
end($this->data_list);
return key($this->data_list);
}
//判断某个键值是否存在
private function ifExistKey($key){
if(array_key_exists($key, $this->data_list)){
return true;
}
return false;
}
//查找尾结点
public function findLastNode(){
foreach($this->data_list as $key=>$value){
if($value->getNext() === NULL){
return $key;
}
}
}
}