一、顺序表的概念
顺序表是一段物理地址连续的存储单元,依次存储数据元素的线性结构。分为静态顺序表与动态顺序表。
- 静态顺序表
使用定长数组存储元素,在栈上分配内存,由操作系统自动分配释放。
注意:
( 栈上存储局部变量,局部变量在生命周期之外会被释放内存空间,存储的数据消失。) - 动态顺序表
使用动态开辟的数组存储,在堆上分配内存,由程序员分配释放,若程序员不释放,程序结束时由OS进行回收。
二、顺序表的增删查改
1、顺序表结构体
typedef int SLDataType;
使用类型重定义来实现 int、double 等数据类型的替换,便于顺序表存储不同类型数据时类型的修改。
#define TYPE “%d”
需要对应输出格式的宏定义来完成输出格式的修改。
typedef int SLDataType;
typedef struct SeqList
{
SLDataType *arry;//指向动态开辟的数组
size_t size;//有效数据的个数
size_t capicity;//容量空间的大小
}SeqList;
2、顺序表初始化
void SeqListInit(SeqList* ps,int InitCapicity)// InitCapicity为申请的动态空间内存数目
{
ps->arry = (SLDataType *)malloc(sizeof(SLDataType)*InitCapicity);
if (NULL == ps->arry){//判断是否申请成功
perror("malloc");
return;
}
ps->capicity = InitCapicity;
ps->size = 0;
//printf("ps->arry:%p\n",ps->arry);
void SeqListInit(SeqList* ps,int InitCapicity);
ps为一级指针,存储L的地址,通过ps为arry申请动态内存等同于通过L申请,因为arry的地址是一样的。
3、顺序表数据增加
添加数据过程:根据提示输入数据,(若存储空间不够,则自动扩容,并给出扩容成功的提示),输入-1时退出输入。
void SeqListAdd(SeqList* p)
{
assert(p);
int num = 0;
int temp = 0;
printf("请输入要存储的数字(输入-1则结束输入):\n");
while (!temp){
if (p->size < p->capicity||SeqListDilita(p)){//SeqListDilita(p)为扩容
scanf(TYPE, &num);
if (num==EOF){
break;
}
p->arry[p->size]=num;
p->size++;
}
system("cls");
}
}
通过 || 运算实现自动扩容:
if (p->size < p->capicity||SeqListDilita§)
若空间足够
(即size<capicity,此时if 为真,不考虑扩容),正常输入数据
若空间已满
(即size==capicity,因 || 运算A和B都为假时才为假,调用扩容函数),扩容成功再继续输入数据
扩容函数
realloc 实现扩容,realloc扩容返回新空间的首地址,扩容成功则返回1并输出“扩容成功”,扩容失败则返回0
int SeqListDilita(SeqList *p)//扩容成功返回1,失败返回0
{
p->arry = (SLDataType *)realloc(p->arry,sizeof(SLDataType)*(p->capicity+NewSize));
if (NULL == p->arry){
perror("malloc");
return 0;
}
p->capicity = p->capicity + NewSize;
printf("扩容成功!\n");
return 1;
}
4、顺序表删除
该算法删除线性表中所有值为x的元素
(1)记录值为x元素的个数count
(2)对值不为x的元素,向前移动count个单位
(3)顺序表长减去count
void SeqListDelete(SeqList* p)
{
int num = 0;
SeqListPrint(p);
printf("\n请输入你要删除的数:");
scanf(TYPE, &num);
int count = 0;
for (int i = 0; i < (p->size); i++){
if (num == p->arry[i]){
count++;
}
else{
p->arry[i-count] = p->arry[i];
}
}
p->size = p->size - count;
}
删除线性表中所有值为x的元素:
5、顺序表查找
通过 for 循环遍历,按照 arr[i]==num 的格式输出要查找的数
void SeqListFind(SeqList* p)
{
int num = 0;
printf("请输入你要查找的数:");
scanf(TYPE, &num);
for (int i = 0; i < p->size; i++){
if (num == p->arry[i]){
printf("arr[%d]==%d\n", i, num);
}
}
}
按照 arr[i]==num 的格式输出要查找的数:
6、顺序表修改
for 循环遍历找到你要修改的数,然后对你要修改的数一一修改
void SeqModification(SeqList* p)
{
int num = 0;
SeqListPrint(p);
printf("\n请输入你要修改的数:");
scanf("%d", &num);
for (int i = 0; i < p->size; i++){
if (num == p->arry[i]){
int temp = 0;
printf("arry[%d]==%d请输入数字:\n",i,num);
scanf(TYPE, &temp);
p->arry[i] = temp;
}
}
}
顺序表修改:
7、顺序表打印
通过调用 SeqListPrint(),实现打印顺序表,查看顺序表内容的功能,若顺序表为空,则打印结果为 NULL!
void SeqListPrint(SeqList* p)
{
int Size = p->size;
printf("顺序表内容为:");
if (Size == 0){
printf("NULL!\n");
}
else{
for (int i = 0; i < Size; i++){
printf(TYPE1, p->arry[i]);
}
printf("\n");
}
}
打印顺序表内容:
三、源码
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<windows.h>
#include<assert.h>
#define NewSize 3
#define TYPE "%d"
#define TYPE1 "%d "//输出格式要求间距为一个空格
typedef int SLDataType;
typedef struct SeqList
{
SLDataType *arry;//指向动态开辟的数组
size_t size;//有效数据的个数
size_t capicity;//容量空间的大小
}SeqList;
void SeqListInit(SeqList* ps,int InitCapicity)
{
ps->arry = (SLDataType *)malloc(sizeof(SLDataType)*InitCapicity);
if (NULL == ps->arry){
perror("malloc");
return;
}
ps->capicity = InitCapicity;
ps->size = 0;
printf("ps->arry:%p\n",ps->arry);
}
int SeqListDilita(SeqList *p)
{
p->arry = (SLDataType *)realloc(p->arry,sizeof(SLDataType)*(p->capicity+NewSize));
if (NULL == p->arry){
perror("malloc");
return 0;
}
p->capicity = p->capicity + NewSize;
printf("扩容成功!\n");
return 1;
}
void SeqListAdd(SeqList* p)
{
assert(p);
int num = 0;
int temp = 0;
printf("请输入要存储的数字(输入-1则结束输入):\n");
while (!temp){
if (p->size < p->capicity||SeqListDilita(p)){
scanf(TYPE, &num);
if (num==EOF){
break;
}
p->arry[p->size]=num;
p->size++;
}
//printf("退出:1 ##### 继续:0\n");
//scanf("%d",&temp);
system("cls");
}
}
void SeqListPrint(SeqList* p)
{
int Size = p->size;
printf("顺序表内容为:");
if (Size == 0){
printf("NULL!\n");
}
else{
for (int i = 0; i < Size; i++){
printf(TYPE1, p->arry[i]);
}
printf("\n");
}
}
void SeqListFind(SeqList* p)
{
int num = 0;
printf("请输入你要查找的数:");
scanf(TYPE, &num);
for (int i = 0; i < p->size; i++){
if (num == p->arry[i]){
printf("arr[%d]==%d\n", i, num);
}
}
}
//该算法删除线性表中所有值为x的元素
//记录值为x元素的个数count
//对值不为x的元素,向前移动count个单位
//顺序表长减去count
void SeqListDelete(SeqList* p)
{
int num = 0;
SeqListPrint(p);
printf("\n请输入你要删除的数:");
scanf(TYPE, &num);
int count = 0;
for (int i = 0; i < (p->size); i++){
if (num == p->arry[i]){
count++;
}
else{
p->arry[i-count] = p->arry[i];
}
}
p->size = p->size - count;
}
void SeqModification(SeqList* p)
{
int num = 0;
SeqListPrint(p);
printf("\n请输入你要修改的数:");
scanf("%d", &num);
for (int i = 0; i < p->size; i++){
if (num == p->arry[i]){
int temp = 0;
printf("arry[%d]==%d请输入数字:\n",i,num);
scanf(TYPE, &temp);
p->arry[i] = temp;
}
}
}
void TestSqList()
{
TestSqList1();
}
void TestSqList1()
{
SeqList L;
SeqListInit(&L,3);
SeqListAdd(&L);
SeqListPrint(&L);
SeqListFind(&L);
SeqListDelete(&L);
SeqModification(&L);
SeqListPrint(&L);
free(L.arry);
L.arry = NULL;
}
int main()
{
SeqList L;
TestSqList();
system("pause");
return 0;
}
四、小结
顺序表的学习需要理解顺序表的结构,了解顺序表的动态内存是在堆上申请的,并且该空间是由程序员释放的,若程序员未释放,则在程序结束时由OS进行回收,因此顺序表的内容并不会在某一个函数结束以后遭到空间释放而导致的数据丢失。因此顺序表的内容可以通过一级指针访问,修改。