数据结构——顺序表
前言
顺序表就是在内存中开辟一段连续的存储空间,并给它一个名字进行标识。只有定义了一个顺序表,才能利用该顺序存放数据元素,也才能对该顺序表进行各种操作。
定义顺序表有两种方法:一个是静态定义一张顺序表;二是动态生成一张顺序表。接下来将使用C语言实现。
一、静态顺序表
代码如下:
/**
* 静态顺序表
*
* 采用数组的方法定义:
* 定义数组最大长度 #define MaxSize 100
* 数组类型 ElemType Sqlist[MaxSize]
* 数组实际长度 int len
*
* 简单方式: int Sqlist[100];
*
* 静态定义的顺序表开辟在内存的静态区(函数栈上),这个区域内存
* 会随着函数调用的完成而被系统自动收回
*
*/
#include <stdio.h>
// 顺序表最大长度
#define MaxSize 100
// 定义静态顺序表
int Sqlist[MaxSize];
// 顺序表实际长度
int sqlist_len;
// 向顺序表中插入元素
void InsertElem(int sqlist[], int len, int i, int item)
{
//向顺序表中第i个位置插入item,该顺序表原长度为len
int t;
// 判断非法插入
if(len == MaxSize || i < 1 || i >len+1)
exit(0);
// 将i-1以后的元素向后移动
for(t = len-1; t > i-1; t--)
Sqlist[t+1] = Sqlist[t];
// 插入元素
Sqlist[i-1] = item;
// 顺序表长度加1
sqlist_len += 1;
}
// 从静态表中删除第i个位置元素
void DelElem(int sqlist[], int len, int i)
{
int t;
// 判断非法删除
if(i<1 || i>len)
exit(0);
// 将第i个位置以后的元素依次前移
for(t = i; t < len; t++)
{
sqlist[t-1] = sqlist[t];
}
// 顺序表长度减1
sqlist_len--;
}
二、动态顺序表
代码如下:
/**
* 动态生成顺序表
*
* 其内存空间开辟在内存的动态区,也就是堆内存上,这个区域的内存
* 空间不会被系统自动回收,需要程序主动去释放。
*/
#define MaxSize 100
typedef struct{
int *elme; //顺序表首地址
int length; //表的长度
int listsize; //存储空间容量
}Sqlist;
// 初始化动态顺序表
void initSqlist(Sqlist *L)
{
// 动态开辟空间
L->elme = (int *)malloc(MaxSize*sizeof(int));
if(!L->elme)
exit(0);
L->length = 0; // 表长为0
L->listsize = MaxSize; // 表的大小为MaxSize
}
// 向该顺序表中第i个位置插入item
void InsertElem(Sqlist *sqlist, int i, int item)
{
int *base, *insertPtr, *p;
// 检测非法插入
if(i<1 || i > sqlist->length+1)
exit(0);
//追加空间
if(sqlist->length >= sqlist->listsize)
{
base = (int *)realloc(sqlist->elme,(sqlist->listsize+10)*sizeof(int*));
sqlist->elme = base; // 更新内存基地址
// 存储空间增大10
sqlist->listsize = sqlist->listsize + 10;
}
// insertPtr为插入位置
insertPtr = &(sqlist->elme[i-1]);
for(p = &(sqlist->elme[sqlist->length-1]); p >= insertPtr; p-- )
{
// 将i-1以后的元素顺序移后一个元素位置
*(p+1) = *(p);
}
*insertPtr = item; //第i个位置插入元素
sqlist->length ++; //表长加1
}
void DelElem(Sqlist *sqlist, int i)
{
int *delItem, *p;
// 判断非法删除
if(i<1 || i>sqlist->length)
exit(0);
delItem = &(sqlist->elme[i-1]);
p = &(sqlist->elme[sqlist->length-1]);
for(; delItem < p; delItem++)
{
*(delItem+1) = *delItem;
}
// 顺序表长度减1
sqlist->length--;
}
// 释放内存
void FreeMemory(Sqlist *sqlist)
{
/**
* 1. 就算没有free(),main()结束后也是会自动释放malloc()的内存的,
* 这里监控者是操作系统,设计严谨的操作系统会登记每一块给每一个应用程序分配的内存,
* 这使得它能够在应用程序本身失控的情况下仍然做到有效地回收内存。
*
* 2. free()的用处在于实时回收内存。
* 如果你的程序很简单,那么你不写free()也没关系,
* 在你的程序结束之前你不会用掉很多内存,
* 不会降低系统性能;而你的程序结束之后,
* 操作系统会替你完成这个工作。
* 但你开始开发大型程序之后就会发现,
* 不写free()的后果是很严重的。
* 很可能你在程序中要重复10k次分配10M的内存,
* 如果每次使用完内存后都用free()释放,
* 你的程序只需要占用10M内存就能运行;
* 但如果你不用free(),那么你的程序结束之前就会吃掉100G的内存。
* 这其中当然包括绝大部分的虚拟内存,
* 而由于虚拟内存的操作是要读写磁盘,
* 因此极大地影响系统的性能。
* 你的系统很可能因此而崩溃。
*
* 3. 任何时候都为每一个malloc()写一个对应的free()是
* 一个良好的编程习惯。这不但体现在处理大程序时的必要性上,
* 更体现在程序的优良的风格和健壮性上。
* 毕竟只有你自己的程序知道你为哪些操作分配了哪些内存以及
* 什么时候不再需要这些内存。
* 因此,这些内存当然最好由你自己的程序来回收。
*
*/
free(sqlist); // 释放掉申请的存储空间
sqlist = NULL; // 将指针指向空
}
说明
以上程序是根据数据结构的定义进行的实践操作,相关说明已在程序中有注释。因个人对数据结构理解不同,代码实现可能也会不同,以上仅供参考。