第七课 — 线性表的顺序存储结构

线性表的顺序存储结构(重点)

顺序存储的定义:线性表的顺序存储结构,指的是用一段地址连续的存储单元依次存储线性表的数据元素。

 

 首先创建一个.h文件,把所有的函数的api函数写出来。

具体如下:首先创建线性表,销毁线性表,清除线性表,线性表的深度,线性表的容量,线性表的插入,获取线性表的某一个数,删除线性表的某一个数。

#ifndef __SEQLIST.H
#define __SEQLIST.H

typedef void SeqList;
typedef void SeqListNode;

SeqList * SeqList_Create(int capacity);

void SeqList_Destroy(SeqList * list);

void SeqList_Clear(SeqList * list);

int SeqList_Length(SeqList * list);

int SeqList_Capacity(SeqList * list);

int SeqList_Insert(SeqList * list, SeqListNode * node, int pos);

SeqListNode * SeqList_Get(SeqList * list, int pos);

SeqListNode * SeqList_Delete(SeqList * list, int pos);

#endif
#include <stdio.h>
#include <SeqList.h>
#include <malloc.h>

typedef unsigned int TSeqListNode;  //4字节

typedef struct _tag_SeqList
{
    int capacity;
    int length;
    TSeqListNode * node;
}Tseqlist;

seqlist * SeqList_Create(int capacity)
{
    Tseqlist* ret = NULL;

    if( capacity >= 0)
    {
        ret = (Tseqlist *)malloc(sizeof(Tseqlist) + sizeof(TSeqListNode) * capacity);
    }

    if( ret != NULL)
    {
        ret->capacity = capacity;
        ret->length = 0;
        ret->node = (TSeqListNode *)(ret + 1);
    }

    return ret;
}

void SeqList_Destroy(SeqList* list) 
{
    free(list);
}

void SeqList_Clear(SeqList* list) 
{
    Tseqlist * sList = (Tseqlist *)list;   //void类型的list强转为结构体类型的线性表

    if( sList != NULL)
    {
        sList->length = 0;
    }
}

int SeqList_Length(SeqList* list) 
{
    Tseqlist * sList = (Tseqlist *)list;
    int ret = -1;

    if( sList != NULL )
    {
        ret = sList->length;
    }
}

int SeqList_Capacity(SeqList* list) 
{
    Tseqlist * sList = (Tseqlist *)list;
    int ret = -1;

    if( sList != NULL )
    {
        ret = sList->capacity;
    }
    
    return ret;
}

int SeqList_Insert(SeqList* list, SeqListNode* node, int pos)
{
    TSeqList* sList = (TSeqList*)list;
    int ret = (sList != NULL);
    int i = 0;

    ret = ret && (sList->length + 1 <= sList->capacity);
    ret = ret && (0 <= pos);

    if(ret)
    {
        if(pos >= sList->length)
        {
            pos = sList->length;
        }

        for(i = sList->length; i>pos; i--)
        {
            sList->node[i] = sList->node[i-1];
        }

        sList->node[i] = (TSeqListNode)node;

        sList->length++;
    }
}

SeqListNode* SeqList_Get(SeqList* list, int pos)
{
    TSeqList* sList = (TSeqList*)list;
    SeqListNode* ret = NULL;

    if( (sList != NULL) && (0 <= pos) && (pos < sList->length) )
    {
        ret = (SeqListNode*)(sList->node[pos]);
        //ret = (SeqListNode*)(sList->node[pos-1]);
    }

    return ret;
}

SeqListNode* SeqList_Delete(SeqList* list, int pos)
{
    TSeqList* sList = (TSeqList*)list;
    SeqListNode* ret = SeqList_Get(list, pos);
    int i = 0;

    if( ret != NULL )
    {
        for(i=pos+1; i<sList->length; i++)
        {
            sList->node[i-1] = sList->node[i];
        }
        
        sList->length--;
    }
    
    return ret;
}

 编写main.c的测试函数:首先创建一个容量为5的线性表;

定义5个变量,一次插入到线性表的第一个位置,然后依次打印出线性表的元素。

 再依次删除线性表,最后解散线性表:函数实现如下

#include <stdio.h>
#include <stdlib.h>
#include "SeqList.h"

int main(int argc, char *argv[]) 
{
    SeqList* list = SeqList_Create(5);
    
    int i = 0;
    int j = 1;
    int k = 2;
    int x = 3;
    int y = 4;
    int z = 5;
    int index = 0;
    
    SeqList_Insert(list, &i, 0);
    SeqList_Insert(list, &j, 0);
    SeqList_Insert(list, &k, 0);
    SeqList_Insert(list, &x, 0);
    SeqList_Insert(list, &y, 0);
    SeqList_Insert(list, &z, 0);
    
    for(index=0; index<SeqList_Length(list); index++)
    {
        int* p = (int*)SeqList_Get(list, index);   //得到每个元素的地址,强制转换成插入类型的指针,解引用得到元素。
        
        printf("%d\n", *p);
    }
    
    printf("\n");
    
    while( SeqList_Length(list) > 0 )
    {
        int* p = (int*)SeqList_Delete(list, 0);
        
        printf("%d\n", *p);
    }
    
    SeqList_Destroy(list);
    
    return 0;
}

 gcc运行其结果如下:

由于容量为5,所以虽然我们把Z = 5 插入线性表,但是其容量已经满了,所以5没有插入线性表。打印结果的线性表的第一个数为最后插入的4,依次为3,2,1,0。

删除函数,是从第0位置开始删除,所以是4,3,2,1,0。

当然也是可以支持输入浮点数的,把插入元素类型换成浮点数,更改如下

 

#include <stdio.h>
#include <stdlib.h>
#include "SequenceList.h"


int main(int argc, char *argv[]) 
{
    SeqList* list = SequenceList_Create(5);//创建容量为5的线性表
    
    double i = -100.100;
    double j = 99.99;
    double k = 98.98;
    double x = 97.97;
    double y = 96.96;
    double z = 95;
    double index = 0;
    SequenceList_Insert(list, &i, 0);//插入元素,每次都是插入在0的位置,那么最后的排列顺序和插入顺序刚好相反
    SequenceList_Insert(list, &j, 0);
    SequenceList_Insert(list, &k, 0);
    SequenceList_Insert(list, &x, 0);
    SequenceList_Insert(list, &y, 0);
    
    SequenceList_Insert(list, &z, 1000);//只有5个单位的容量,多余的插入不起作用
    

    for(index=0; index<SequenceList_Length(list); index++)
    {
        double* p = (double*)SequenceList_Get(list, index);//得到每个元素的地址,强制转成插入类型的指针,解引用得到元素
        
        printf("%f\n", *p);
    }
    
    printf("\n");
    
    while( SequenceList_Length(list) > 0 )
    {
        double* p = (double*)SequenceList_Delete(list, 0);//delete的返回值是删除的元素的地址
        
        printf("%f\n", *p);
    }
    
    SequenceList_Destroy(list);//释放堆空间
    
    return 0;
}

 

我们插入浮点数就OK,我们的代码是和类型无关的。它运行如下:

但是我们切不可犯了低级错误,插入不同类型的元素,比如,你要么插入int类型的,要么插入浮点类型的,

不能第一个插入folat,第二个又插入int,这是犯了概念错误,线性表元素类型必须相同。

 

WARNING:

还有,在运行这个代码的时候你的编译器或许会给出警告:

 

从指针转换为不同大小的整数。我们的编译器是64位的,指针是8个字节,但是我们使用的是typedef unsigned int TSeqListNode;这样一个四个字节的容器来存放8个字节的数据,显然是会出问题的(运行将导致段错误)。但要是你的编译器是32位的则不会出现问题,这也就是为什么我说可能你运行会出现这样的警告。知道了问题所在,那么我们就要改进代码,更改头文件增加如下内容:

#define Compiler_64Bit

#ifdef  Compiler_32Bit
    typedef unsigned int TSeqListNode;//为了存放一个指针强制类型转化后的值
#endif

#ifdef  Compiler_64Bit
    typedef long long TSeqListNode;//为了存放一个指针强制类型转化后的值
#endif

通过条件编译,选择不同大小的容器存放指针。这样之后(在freertos中经常看到这种用法),使用多少位的编译器对应开启多少位的宏,可移植性得到大大的增强。

 

  

 

下一节给答案。

 

posted @ 2017-07-14 10:24  Liu_Jing  Views(311)  Comments(0Edit  收藏  举报