一.概述:
二.顺序表:
1.概念:
2.顺序表的实现:
1)静态分配:
比如数组,数组大小一旦确定,就不可以再被改变。
ElemType代表数据类型,比如整型,浮点型等。
例如:
#include<stdio.h>
#define MaxSize 10 //定义最大长度
typedef struct
{
int data[MaxSize]; //用静态的“数组”存放数据元素,最多存MaxSize个,且为int型,共4*10个字节
int length; //顺序表的当前长度 ,共4个字节
}SqList; //顺序表的类型定义
//基本操作 - 初始化一个顺序表
void InitList(SqList &L)
{
for(int i=0;i<MaxSize;i++)
{
L.data[i]=0; //将所有数据元素设置为默认初始值 ,可省
}
L.length=0; //顺序表初始长度为0 ,因为一开始没存元素
}
int main()
{
SqList L; //声明一个顺序表
InitList(L); //初始化顺序表
//...未完待续,后续操作
return 0;
}
上述代码将所有数据元素设置为默认初始值(InitList函数里)虽然可以省略,但还是会出问题,即如下代码:
如果没有初始化,访问数据到MaxSize,运行结果会有“脏数据”;
如果没有初始化,访问数据到length(顺序表的当前长度),运行结果不会走for循环,因为不初始化,意味着数组长度为0,就无法循环打印数组内容;
InitList函数里给顺序表长度length初始化为0不可省,因为无法预知在这小片的内存区域内之前存放的是什么数据,而且有的编译器默认给初始值,有的默认不给,为了保险,不可省初始化顺序表长度
注意:
静态分配局限性:“数组”长度不可调。
2)动态分配:
动态分配:“数组”长度可变。
指针data指向顺序表中的第一个数据元素。
malloc返回一个指向某个存储空间开始地址的指针。
ElemType指代数据类型,如整型,浮点型。
malloc函数和free函数都需要头文件#include<stdlib.h>。
3)实例:
#include<stdio.h>
#include<stdlib.h>
#define InitSize 10 //默认的最大长度
typedef struct
{
int *data; //指示动态分配数组的指针
int MaxSize; //顺序表的最大容量
int length; //顺序表的当前长度
}SeqList;
void InitList(SeqList &L)
{
//用malloc函数申请一片连续的存储空间
L.data = (int *)malloc( InitSize*sizeof(int) ); //用最大长度乘,因为开辟的是整个空间
L.length = 10; //一开始长度赋值为10,与InitSize(默认的最大长度 )一样
L.MaxSize = InitSize;
}
//增加动态数组的长度
void IncreaseSize(SeqList &L,int len) //len是拓展的长度
{
int *p=L.data; //把L.data给指针p
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); //释放原来的内存空间(长度小的)
}
int main()
{
SeqList L; //声明一个顺序表-->开辟连续的内存空间
InitList(L); //初始化顺序表
//...往顺序表中随便插入几个元素...
IncreaseSize(L,5);
return 0;
}
三.顺序表的实现:
1.顺序表的特点:
-
随机访问,即可以在O(1)时间内找到第i个元素,因为顺序表是连续的,找到一个元素,剩下的元素加/减n(n为自然数)个字节就可以找到指定元素
-
存储密度高,每个节点只存储数据元素(链式存储还存地址)
-
拓展容量不方便(即便采用动态分配的方式实现,拓展长度的时间复杂度也比较高)
-
插入和删除操作不方便,需要移动大量元素