1、程序表的定义

程序表是用一组地址间断的存储单元顺次存储线性表中的数据元素。把逻辑上相邻的元素存储在物理地位上也相邻的存储单元中,元素之间的关系由存储单元的邻接关系来体现。顺序存储构造如下图所示:

留神:线性表中的位序是从1开始的,而数组元素的下标是从0开始的。

2、程序表的实现

2.1 动态调配

#define MaxSize 10  //定义最大长度typedef int ElemType;typedef struct {    ElemType data[MaxSize];  //用动态数组存放数据元素    int length;              //程序表的以后长度} SqList;                    //程序表的类型定义/** * 基本操作-初始化一个程序表 * @param L */void InitList(SqList &L) {    for (int i = 0; i < MaxSize; ++i) {        L.data[i] = 0;  //将所有数据设为默认初始值,否则会有脏数据    }    L.length = 0;  //程序表初始长度为0}

在动态调配时,数组的大小和空间是固定的,无奈更改,一旦空间占满,再退出新的数据就会产生溢出,进而导致程序解体。

思考:如果一开始就申请很大的内存空间呢 ???会存在什么问题 ??? 节约!!

2.2 动态分配

#define InitSize 10  //默认的最大长度typedef int ElemType;typedef struct {    ElemType *data;    //批示动态分配数组的指针    int MaxSize;  //程序表的最大容量    int length;   //程序表的以后长度} SeqList;void InitList(SeqList &L) {    //用malloc函数申请一片间断的内存空间    L.data = (int *) malloc(InitSize * sizeof(int));    L.length = 0;    L.MaxSize = InitSize;}

用malloc函数申请一片间断的存储空间。malloc函数返回一个指针,须要强制转型为你定义的数据元素类型指针。

减少数组空间的办法:

/** * 扩容 * @param L * @param len */void IncreaseSize(SeqList &L, int len) {    int *p = L.data;    L.data = (int *) malloc((L.MaxSize + len) * sizeof(int));    for (int i = 0; i < L.length; i++) {        L.data[i] = p[i];         //将数据复制到新区域    }    L.MaxSize = L.MaxSize + len;  //程序表最大长度减少len,事件开销大    free(p);                      //开释原来的内存空间}

留神:动态分配并不是链式存储,它同样属于顺序存储构造,物理构造没有变动,仍然是随机存取形式,只是调配的空间大小能够在运行时动静决定。

3、程序表的特点

随机拜访,即能够通过首地址和元素序号在O(1) 工夫内找到第 i 个元素;

②存储密度高,每个节点只存储数据元素;

③逻辑上相邻的元素物理上也相邻,扩容、插入、删除操作不不便。

4、程序表上基本操作的实现(以动态调配的程序表为例)

4.1 插入操作

在程序表的第 i 个地位插入新元素,要将第 i 个及其后的所有元素往后挪动一个地位,腾出一个空位插入新的元素

逻辑构造:

代码实现:

/** * 插入的代码,能解决异常情况 * @param L * @param i * @param e * @return */bool ListInsert(SeqList &L, int i, int e) {    if (i < 1) {  //判断i的范畴是否无效        return false;    }    if (L.length >= L.MaxSize) {       //以后存储空间已满,要扩容        IncreaseSize(L, 1);    }    for (int j = L.length; j >= i; j--) {  //将第 i 个元素及之后的元素后移        L.data[j] = L.data[j - 1];    }    L.data[i - 1] = e;                  //在 i 处放 e    L.length++;                         //长度加1    return true;}

工夫复杂度:

最好状况:新元素插入到表尾,不须要挪动元素,i = n + 1,循环0次,O(1)

最坏状况:新元素插入到表头,须要挪动全副元素,i = 1,循环n次,O(n)

均匀状况:假如新元素插入到任何一个地位的概率雷同,即 i = 1,2,3,4......length+1的概率都是 1/(n+1),均匀工夫 复杂度 O(n)

4.2 删除操作

删除第 i 个元素,须要将第 i + 1 个元素及其前面的所有元素往前挪动一个地位

逻辑构造:

代码实现:

/** * 删除数据 * @param L 要操作的列表 * @param i 删除第i个元素,从1开始计数 * @param e 保留删除的元素 * @return */bool ListDelete(SeqList &L, int i, int &e) {    if (i < 1 || i > L.length) {  //判断i的范畴是否无效        return false;    }    e = L.data[i - 1];           //将被删除的元素赋值给e    for (int j = i; j < L.length; j++) {  //将第i个地位后的元素前移        L.data[j - 1] = L.data[j];    }    L.length--;                //线性表长度减1    return true;}

工夫复杂度:

最好状况:删除表尾元素,不须要挪动其余元素,i = n ,循环0次,O(1)

最坏状况:删除表头元素,须要将后续的 n + 1 个元素全副向前挪动,i = 1,循环 n - 1 次,O(n)

均匀状况:假如删除任何一个元素的概率雷同,即 i = 1,2,3,4......length+1的概率都是 1/n,均匀工夫复杂度 O(n)

4.3 按位查找

获取表中第 i 个地位的元素值

ElemType GetElem(SqList L, int i) {    return L.data[i - 1];}

工夫复杂度 O(1)

4.4 按值查找

在表中查找元素值等于指定值的元素,并返回其位序

/** * 按值查找 * @param L * @param e * @return */int LocateElem(SqList L, int e) {    for (int i = 0; i < L.length; ++i) {        if (L.data[i] == e) {            return i + 1;        }    }    return 0;}

工夫复杂度:

最好状况:指标元素在表头,循环 1 次,O(1)

最坏状况:指标元素在表尾,循环 n 次,O(n)

均匀状况:假如指标元素呈现在任何一个地位的概率雷同,都是 1/n,均匀工夫复杂度 O(n)