PHP数据结构与算法:顺序表

一、概念

把线性表的结点按逻辑顺序依次存放在一组地址连续的存储单元里,元素间的顺序关系由它们的存储顺序自然表示。

  • 逻辑顺序与物理顺序一致
  • 元素之间的关系以元素在计算机内的“物理位置相邻”来体现
二、基本形式

图a)顺序表的基本形式,数据元素本身连续存储,每个元素的存储单元固定大小相同。元素的下标是逻辑地址,元素的物理地址(内存实际地址)可以通过存储区的起始地址Loc(e0)加上逻辑地址(第i个元素)与存储单元大小(c)的乘积计算而得,所以访问指定元素不用从头遍历即可通过计算得到地址,时间复杂度为O(1):

Loc(ei) = Loc(e0) + i*c

图b)顺序表的元素外置形式,将实际数据元素另行存储,而顺序表中各单元位置保存对应元素的地址信息。也被称为对实际数据的索引,是最简单的索引结构。

三、结构与基本实现

1.结构

顺序表的完整信息包含两部分,一部分是为实现正确操作而需记录的信息,称为顺序表表头区。表头区信息主要包括元素存储区的容量和当前表中已有的元素个数两项。另一部分是表中元素集合。

2.基本实现方式

顺序表的基本实现有一体式结构和分离式结构。

图a)一体式结构,存储表信息的单元与元素存储区以连续的方式安排在一块存储区里,两部分数据的整体形成一个完整的顺序表对象。一体式结构整体性强,易于管理。但是由于数据元素存储区域是表对象的一部分,顺序表创建后,元素存储区就固定了。

图b)分离式结构,表对象里只保存与整个表有关的信息(容量和元素个数),实际数据元素存放在另一个独立的元素存储区里,通过链接与基本表对象关联。

元素存储区替换:

一体式结构由于顺序表信息区与数据区连续存储在一起,所以若想更换数据区,则只能整体搬迁,即整个顺序表对象(指存储顺序表的结构信息的区域)改变了。 

分离式结构若想更换数据区,只需将表信息区中的数据区链接地址更新即可,而该顺序表对象不变。

元素存储区扩充:

分离式结构的顺序表,若将数据区更换为存储空间更大的区域,则可以在不改变表对象的前提下对其数据存储区进行了扩充,所有使用这个表的地方都不必修改。只要程序的运行环境(计算机系统)还有空闲存储,这种表结构就不会因为满了而导致操作无法进行。人们把采用这种技术实现的顺序表称为动态顺序表,因为其容量可以在使用中动态变化。

  • 每次扩充增加固定数目的存储位置,如每次扩充增加10个元素位置,这种策略可称为线性增长。  特点:节省空间,但是扩充操作频繁,操作次数多。
  • 每次扩充容量加倍,如每次扩充增加一倍存储空间。  特点:减少了扩充操作的执行次数,但可能会浪费空间资源。以空间换时间,推荐的方式。

四、顺序表的PHP实现
<?php

/**
 * 顺序表基本操作
 * 1.顺序表是否为空            isEmpty
 * 2.顺序表是否已满            isFull
 * 3.获取某一位置的元素         getItem
 * 4.修改某一位置的元素         setItem
 * 5.删除某一位置的元素(保序)   delItem
 * 6.根据值查找元素首次出现位置   getLocation
 * 7.统计元素的个数            count
 * 8.顺序表末尾插入元素         append
 * 9.顺序表任意位置插入元素      add
 * 10.输出顺序表               printList
 * 11.销毁顺序表               clear
 */

class SeqList
{
    /**
     * 顺序表默认最大常量
     */
    const MAX = 80;

    /**
     * 顺序表最大容量,默认80
     * @var int
     */
    private $max;

    /**
     * 元素个数
     * @var int
     */
    private $num;

    /**
     * 具体元素
     * @var array
     */
    private $item;

    /**
     * 构造方法
     * @param int $max
     */
    public function __construct($max = self::MAX)
    {
        $this->max = $max;
        $this->num = 0;
        $this->item = new SplFixedArray(self::MAX);
    }

    /**
     * 是否为空
     * @return bool
     */
    public function isEmpty()
    {
        return empty($this->num);
    }

    /**
     * 顺序表是否已满
     * @return bool
     */
    public function isFull()
    {
        return $this->num >= self::MAX;
    }

    /**
     * 修改某一位置的元素
     * @param $index
     * @param $value
     * @return bool
     * @throws Exception
     */
    public function setItem($index,$value)
    {
        try{
            if(!is_int($index)){
                throw new Exception($index);
            }
            if(0 <= $index && $index < $this->num){
                $this->item[$index] = $value;
            }else{
                throw new Exception($index);
            }
        }catch (TypeError $e){
            echo $e->getMessage();
        }catch (RuntimeException $e){
            echo $e->getMessage();
        }
        return true;
    }

    /**
     * 获取某一位置的元素
     * @param $location
     * @return mixed
     * @throws Exception
     */
    public function getItem($index)
    {
        try{
            if(!is_int($index)){
                throw new Exception($index);
            }
            if(0 <= $index && $index < $this->num){
                return $this->item[$index];
            }else{
                throw new Exception($index);
            }
        }catch (TypeError $e){
            echo $e->getMessage();
        }catch (RuntimeException $e){
            echo $e->getMessage();
        }
    }

    /**
     * 删除某一位置的元素
     * @param $index
     * @throws Exception
     */
    public function delItem($index)
    {
        try{
            if(!is_int($index)){
                throw new Exception($index);
            }
            if($index < 0 || $index >= $this->num) {
                throw new RuntimeException($index);
            }
        }catch (TypeError $e){
            echo $e->getMessage();
        }catch (RuntimeException $e){
            echo $e->getMessage();
        }
        for($i = $index;$i < $this->num;$i++){
            $this->item[$i] = $this->item[$i+1];
        }
        $this->num--;
    }

    /**
     * 根据值查找元素首次出现位置
     * @param $value
     * @return int|string
     */
    public function getLocation($value)
    {
        for($i = 0;$i < $this->num;$i++){
            if($this->item[$i] == $value){
                return $i;
            }
        }
        return -1;
    }

    /**
     * 统计元素的个数
     * @return int
     */
    public function count()
    {
        return $this->num;
    }

    /**
     * 顺序表末尾插入元素
     * @param $value
     */
    public function append($value)
    {
        if($this->isFull()){
            echo '表存储已满。';
            return;
        }else{
            $this->item[$this->num] = $value;
            $this->num++;
        }
    }

    /**
     * 顺序表任意位置插入元素
     * @param $index
     * @param $value
     * @throws Exception
     */
    public function add($index,$value)
    {
        try{
            if(!is_int($index)){
                throw new Exception($index);
            }
            if($index < 0 || $index > $this->num) {
                throw new RuntimeException($index);
            }
        }catch (TypeError $e){
            echo $e->getMessage();
        }catch (RuntimeException $e){
            echo $e->getMessage();
        }
        for($i = $this->num;$i > $index;$i--){
            $this->item[$i] = $this->item[$i - 1];
        }
        $this->item[$index] = $value;
        $this->num++;
    }

    /**
     * 输出顺序表
     */
    public function printList()
    {
        for($i = 0;$i < $this->num;$i++){
            echo $this->item[$i].'-----';
        }
    }

    /**
     * 销毁顺序表
     */
    public function clear()
    {
        $this->__construct();
    }
}

$t = new SeqList();
$t->append('er');
$t->add(1,'er2');
var_dump($t->count()).'<br />';
print_r($t->printList());

//$t->setItem(0,1);
//var_dump($t->getItem(0));

 

转载于:https://my.oschina.net/programs/blog/1648194

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值