数据结构之顺序表

        今天要讲的是数据结构里面的顺序表,顺序表是物理上连续的一种数据结构,和数组类似,其实也就是数组更加规范化,标准化之后定义的一种数据结构。下面就让我们一步一步完成顺序表的实现吧。

1、顺序表的创建

增删查改是我们对一种数据结构的基本操作,作为顺序表也应该方便于我们去进行这样的操作,所以我们的顺序表不能指定空间的大小,需要是动态增长的。所以我们对于这种数据结构的创建应该是下面这样的:

typedef int datatype
struct seqlist
{
    datatype* data;
    int size;
    int capacity;
}

因为我们的顺序表里寸的不一定是整型数据,也可能是浮点型,甚至是结构体类型,所以为了方便我们使用typedef来定义数据类型为datatype,然后我们就需要一个datatype*类型的指针来访问数据,另外创建两个整型,一个size表示元素个数,capacity表示我们顺序表的容量,这样才方便我们判断什么时候进行扩容,也能很方便的访问尾元素。

2、顺序表的初始化

对于我们创建的顺序表来说我们一开始时候data应该是NULL,因为没有元素,所以size应该是0,capacity也是0。

void seqlistInit(struct seqlist* p);

void seqlistInit(struct seqlist* p)
{
    assert(p);
    p->data=NULL;
    p->size=0;
    p->capacity=0;
}

这里多了个assert是来判断传入的指针是否为空,我们对顺序表初始化,即便顺序表为空,我们传入的指针也不应为NULL。 

 3、头插

创建好了顺序表我们就要实现顺序表的各种接口,首先就是头插。

头插就是在不影响其他元素的前提下在头部插入元素,对于我们顺序表来说只能把全部元素后移一个节点,然后把第一个节点改成我们想要的样子。这里要注意容量问题,如果顺序表满了,我们再进行头插就需要扩容。在后移元素的时候还要注意如果从前往后移的话,前面的元素就会把后面的元素给覆盖掉,所以我们应该从尾元素开始后移。

void seqlistPushFront(struct seqlist* p, datatype x);

void seqlistPushFront(struct seqlist* p, datatype x)
{
    if(p->size==p->capacity)
    {
        p->capacity=p->capacity==0?4:2*p->capacity;
        p->data=realloc(p->data,p->capacity*sizeof(datatype));
    }
    struct seqlist* cur = p->data;
    while(p->size--)
    {
        p->data[p->size+1]=p->data[p->size];
    }
    p->data[0]=x;
    p->size++;
}

头插完成之后还应该让我们的size++;

4、头删

有了前面的头插,头删就很容易了,我们首先要把第一个元素删除掉,然后把其他元素前移,这里前移应该从前往后移,不然的话就会导致前面的元素被覆盖。我们可以直接用覆盖代替删除

void seqlistPopFront(struct seqlist* p);

void seqlistPopFront(struct seqlist* p)
{
    assert(p);
    for(int i=1;i<p->size;i++)
    {
        p->data[i-1]=p->data[i];
    }
    p->size--;
}

头删完成之后同样应该让size--;

5、尾插

对于顺序表而言尾插很容易,先判断是否有多余的空间,如果没有就先扩容,然后在尾元素后面加上新元素就可以了。

void seqlistPushBack(struct seqlist* p,datatype x);

void seqlistPushBack(struct seqlist* p,datatype x)
{
    assert(p);
    if(p->size==p->capacity)
    {
        p->capacity=p->capacity==0?4:2*p->capacity;
        p->data=realloc(p->data,p->capacity*sizeof(datatype));
    }
    p->data[p->size-1]=x;
    p->size++;
}

同样的尾插完成size++;

6、尾删

顺序表的尾删是很容易的。只需要让size--就可以了,我们就访问不到尾元素了。至于原来的元素我们不用管,下次尾插就会覆盖掉,或者是顺序表用完直接释放掉。

void seqlistPopBack(struct seqlist* p)
{
    assert(p);
    p->size--;
}

7、查找

查找的话我们就需要遍历顺序表来判断对应位置元素是否为我们需要的元素

void seqlistSearch(struct seqlist* p,datatype x);

datatype* seqlistSearch(struct seqlist* p,datatype x)
{
    assert(p);
    for(int i=0;i<p->size;i++)
    {
        if(p->data[i]==x)
            return p->data+i;
    }
    return NULL;
}

8、修改

修改的话我们可以使用前面的查找接口来找到对应位置,然后修改

void seqlistModify(struct seqlist* p,datatype x,datatype y)
{
    datatype* tmp=seqlistSearch(p,x);
    *tmp=y;
}

9、顺序表的特性

通过前面的接口我们可以发现顺序表在进行头插头删时候效率较低,每次都需要遍历来移动数据,尾插尾删效率很高,只需要操作size。另外顺序表的一大特性是支持随机访问,只要给定访问第几个元素,我们只需要对data加减对应的数据然后解引用就可以访问得到对应位置了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值