概念
线性表的顺序存储(物理)。它是用一组地址连续的存储单元依次存储线性表中的数据元素。它是一种随机存储的存储结构,通常用高级程序设计语言中的数组来描述线性表的顺序存储结构。
线性表是具有相同数据类型的n个数据元素的有限序列,其中n为表长。线性表L一般表示为L=(a1,a2,a3,…,an)。它是一种逻辑结构,表示元素之间一对一的相邻关系。
性质
- 可以按序号随机存取(可以在O(1)时间内找到第i个元素)
- 逻辑上相邻的元素在物理上也相邻
- 表中元素的逻辑顺序与其物理顺序相同
- 存储密度高(每一个结点只会存储数据元素,而不像链式表还要存放指针)
- 拓展容量不方便
- 插入删除元素不方便(均需要移动大量元素)
&是C++中的引用符号,用作函数形参是表明传递的是实参的一个引用(即实参的一个别名),这样在函数中对形参操作会影响到实参,通常用&来通过函数改变实参的值。如果没有&,则传递的只是实参的一个副本,在函数中对形参的操作不会影响到实参。正如例子中,对于L凡涉及到要通过函数修改的它时(如在表中插入元素ListInsert或删除元素ListDelete )L前都有&,不涉及修改变量时(如获取表中元素priorElem,GetElem)L前没有&。
类型定义
静态分配
数组的大小和空间已经固定,一旦空间占满,再加入新的数据就会溢出从而导致程序崩溃。
#define MaxSize 50 //定义线性表的最大长度
typedef struct {
ElemType data[MaxSize];//静态数组存放的数据元素
int length;//当前长度
}SqList;
动态分配
一旦存储空间占满,就会另外开辟出一块更大的空间用以替换原来的存储空间,从而达到扩充存储数组空间的目的。
#include <stdlib.h>//malloc free函数的头文件
#define InitSize 100
typedef struct {
ElemType *data;//指示动态分配数组的指针。类似于空间首地址
int Max,len;//数组的最大容量和当前有效存储单元的个数
}SqList1;
//初始动态分配语句
L.data = (ElemType*)malloc(sizeof(ElemType)*InitSize);
malloc()函数其实就在内存中找一片指定大小的空间,然后将这个空间的首地址范围给一个指针变量,这里的指针变量可以是一个单独的指针,也可以是一个数组的首地址,这要看malloc()函数中参数size的具体内容。我们这里malloc分配的内存空间在逻辑上连续的,而在物理上可以连续也可以不连续。对于我们程序员来说,我们关注的是逻辑上的连续,因为操作系统会帮我们安排内存分配,所以我们使用起来就可以当做是连续的。
我们需要将malloc函数返回的指针强制转型为自己所定义的数据元素类型指针。
关于引用
- C语言中没有引用的存在,引用是在C++里面才有的神级操作。
- 引用&就是给已经存在的变量新建了一个名字,如果程序对引用别名做了某些操作,其实就是对原目标进行了改动。
- C语言中,被调用函数不能直接修改主调函数中变量的值,而只能修改其私有的临时副本的值。
C语言中:
- &运算符:用于取一个对象的地址
- *运算符:作用于指针时表示访问指针所指向的对象
- 指针只能指向某种特定类型的对象,也就是说,每一个指针都必须指向某种特定的数据类型。
总结:
变量a 本质上代表一个存储单元。CPU通过该存储单元的地址访问该存储单元中的数据。所以**a本来代表两个值:存储单元的地址和储单元中的数据。**于是就有了二异性。为了消除这种二义性,C语言规定a表示存储单元中的数据,&a表示存储单元的地址。
a存储单元中的数据可以是一个普通数值,也可以是另一个存储单元的地址,比如:a = &b; 语句就是将b的存储单元的地址存入a存储单元中。C语言规定 *a 代表a中存储的地址对应的存储单元中的数据,也就是访问 *a 就等于访问b,于是 *a提供了通过a访问b中的数据的手段。
a表示a对应的存储单元中的数据。
&a表示a对应的存储单元的地址。
*a 表示:首先,要求a对应的存储单元中的数据一定是另一个存储单元的地址。于是*a表示另一个存储单元中的数据。
当a声明的类型是int*时,a中存储的是一个存储单元的地址,而该存储单元中存储的数据是一个整数数值;通过*a可以访问(读取或修改)这个数值。a == &*a 都是该存储单元的地址。 当a声明的类型是int**时,a中存储的是一个存储单元的地址,而该存储单元中存储的数据是另外一个存储单元的地址,另外这个存储单元中存储的是一个整数数值;通过**a可以访问(读取或修改)这个数值。
int *p;
p = &c;//将c的地址赋值给指针变量p,我们称p为“指向c的指针”
int x;
x = *p;//将p指向的指针所对应的对象赋值给x,所以x就等于c的值。
基本操作
在C语言中,结构体的比较不能直接用“==”,而是需要依次对比各个分量来判断两个结构体是否相等。
#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
#define FALSE1 2
#define OK 1
#define OVERFLOW -2
#define InitSize 10
typedef int ElemType;//数据类型为int型
typedef int Status;//函数类型,其值是函数结果状态码
typedef struct {
ElemType *elem;//指示动态分配数组的指针
int ListSize;//当前所能存储的最大容量
int length;//当前有效存储单元的个数
}SeqList;
void DestroyList(SeqList *ptr);
/**
* 创建顺序表
*/
SeqList creatList(){
// 由系统分配list占用的内存
// SeqList list;
// return list;
//自己动态分配的内存,需要在程序运行之前手动释放占用的内存空间。
SeqList *list = (SeqList*) malloc(sizeof (SeqList));
return *list;
}
/**
* 初始化一个顺序表
* @param L
* @return -2(失败);1(成功)
*/
Status InitList(SeqList *L){
//动态内存分配,返回的是指针型
L->elem = (ElemType*) malloc(InitSize * sizeof (ElemType));
//申请空间失败
if(L->elem==NULL){
return OVERFLOW;
} else{
L->length = 5;
L->ListSize = InitSize;
return OK;
}
}
/**
* 增加动态数组的长度
* @param L
* @param len
* @return -2(失败);1(成功)
*/
Status IncreaseSize(SeqList *L,int len){
int *p = L->elem;
L->elem = (ElemType*) malloc(sizeof (ElemType)*(L->ListSize+len));
if(L->elem==NULL){
return OVERFLOW;
}else{
//将数据复制到新的区域
for(int i=0;i<L->length;i++){
L->elem[i]=p[i];
}
//顺序表最大长度增加len
L->ListSize = L->ListSize + len;
//释放原来的内存空间
free(p);
return OK;
}
}
/**
* 销毁顺序表
* @param L
*/
void DestroyList(SeqList *L){
//重点释放顺序表的存储单元。
//如果顺序表自身的内存也是动态分配的,需要手动释放。
free(L->elem);//释放存储空间
L->length = 0;
L->ListSize = 0;
}
/**
* 按位查找:在第i的位置的元素的值
* @param L
* @param i
* @return
* 时间复杂度:O(1)
*/
ElemType GetElem(SeqList L,int i){
return L.elem[i-1];
}
/**
* 按值查找:查找第一个元素值为e的元素并返回其位序
* @param L
* @param e
* @return
* 时间复杂度:O(n)
*/
int LocateElem(SeqList L,ElemType e){
for(int i=0;i<L.length;i++){
if(L.elem[i]==e){
return i+1;
}
}
return FALSE;
}
/**
* 插入:在i位置插入元素e
* @param L
* @param i
* @param e
* @return
*/
Status ListInsert(SeqList *L,int i,ElemType e){
//判断i的范围是否有效
if(i<1||i>L->length+1){
return FALSE;
}
//当前存储空间已满不能插入
if(L->length>=InitSize){
return FALSE1;
}
//i位置之后的元素后移
for(int j = L->length;j>=i;j--){
L->elem[j]=L->elem[j-1];
}
//i处放入e
L->elem[i-1]=e;
L->length++;
return TRUE;
}
/**
* 删除第i个位置的元素,并用e返回删除元素的值
* @param L
* @param i
* @param e
* @return
*/
Status ListDelete(SeqList *L,int i,ElemType *e){
if(i<1||i>L->length){
return FALSE;
}
*e = L->elem[i-1];
for(int j=i;j<L->length;j++){
L->elem[j-1]= L->elem[j];
}
L->length--;
return TRUE;
}
int main() {
// SeqList L;
// InitList(&L);
SeqList L = creatList();
printf("初始化结果:%d\n",InitList(&L));
printf("增加动态数组结果:%d\n", IncreaseSize(&L,5));
printf("插入元素结果:%d\n", ListInsert(&L,3,5));
printf("按位查找结果:%d\n", GetElem(L,3));
printf("按值查找结果:%d\n", LocateElem(L,5));
int e = -1;
printf("删除操作结果:%d\n", ListDelete(&L,3,&e));
printf("删除元素的值为:%d\n", e);
DestroyList(&L);
return 0;
}
初始化结果:1
增加动态数组结果:1
插入元素结果:1
按位查找结果:5
按值查找结果:3
删除操作结果:1
删除元素的值为:5
今日推歌
—《月亮不会奔你而来》
我不摘月亮
我要它永远高悬天上皎洁流芳
他始终陌生
才允许诸多浪漫想象作为我理想
我要写诗给他
不要求送达
他可以接很多人的鲜花
不必无暇
他也能自在去漫步月球下
别去对号入座
谁爱意将真实灵魂蒸发