1.线性表
线性表呈现出一条线性,用指针把一块一块的内存连接起来。
其余还有树型结构,哈希结构,图结构。
线性表分为:
- 顺序表
- 链表
- 栈
- 队列
- 字符串
1.2顺序表
顺序表就是数组,但在数组的基础上,从头开始存。还要求数据连续存储,不能跳跃间隔。
本质:数组(分为静态和动态)
(顺序表要求连续存储,数据挨着存)
写相对正式的代码要规范。
用宏或条件编译,防止头文件被重复包含。
不仅仅有数组,还要用size标识有多少数组。
凡是多个数组,都用结构体。
完善:
- 对顺序表初始化一下
- 尾插,头插
.h放声明
.cpp放定义
//建立一个头文件SeqList.h,用静态顺序表实现
#pragma once
#define N 1000
//宏的好处让静态的数据表随时转换
//静态顺序表结构
typedef int SLDataType;//想存什么类型就改中间的字母
//想让顺序表存储管理别的东西
//为了一个地方改其他地方都改,定义一个typedef
typedef struct SeqList//结构体typedef
{
SLDataDype a[N];
//最简单的应该有个数组(定义成静态)
//不推荐在这里直接写数字,因为换大小不好换
int size;
//表示数组中存储了多少个有效数据,从头连续存储
}SL;//简写
//向顺序表中插入数据
//对顺序表初始化
//接口函数,给别人用的,对接。--命名风格跟STL走,方便后续学习STL
void SeqListInit( SL* ps);
//尾插数据
void SeqListPushBack( SL* ps, SLDataType x);//用SLDataType做这个地方的类型
//结构体SeqList太长,可typedef一下,变成SL
//尾删
void SeqListPopBack( SL* ps);
//头插
void SeqListPushFront( SL* ps, SLDataType x);
//头删
void SeqListPopFront( SL* ps);
静态顺序表
- 特点:满了不让插入
- 缺点:给多大的空间很难确定n给小不够用,n给大了浪费。
动态顺序表
#pragma once
typedef int SLDataType;
typedef struct SeqList
{
SLDataType* a;//定义成指针
int size;
//表示数组中存储了多少个有效数据,从头连续存储
//提供动态开辟内存的方式malloc,在堆上可以动态开辟内存,不用了可以释放。
//最后不够了把原来的空间释放,开更大的一块空间。叫做扩容。
//现在的结构不足以方便地表示动态顺序表。有一个指针,指向动态开辟的空间。
//增加capacity即容量。表示数组实际能存的空间容量多大。多少个数据
int capacity;
}SL;
SeqList.c
#include "SeqList.h"
#include <stdio.h>
#include <stdlib.h>
//初始化
void SeqListInit(SL ps)
{
//应该用.因为a是成员
ps.a = NULL;
ps.size = ps.capacity = 0;
//最开始对顺序表的初始化
}
//尾插数据
void SeqListPushBack(SL* ps, SLDataType x);//用SLDataType做这个地方的类型
//结构体SeqList太长,可typedef一下,变成SL
//尾删
void SeqListPopBack(SL* ps);
//头插
void SeqListPushFront(SL* ps, SLDataType x);
//头删
void SeqListPopFront(SL* ps);
Test.c
#include "SeqList.h"
//调用函数
void TestSeqList1()
{
SL sl;
//sl未初始化
SeqListInit(sl);//对结构体进行初始化
}
int main()
{
TestSeqList1();
return 0;
}
错误的!!!
sl:实参
ps:形参
实参传给形参。ps形参改变不影响实参
用实参的地址,应该传指针
修改:
void SeqListInit(SL* ps);
ps->a = NULL;
ps->size = ps->capacity = 0;
SeqListInit(&sl);
尾插数据
void SeqListPushBack(SL* ps, SLDataType x)//用SLDataType做这个地方的类型
{
//整个顺序表没有空间
//刚进来只对其进行初始化没有空间
//如果没有空间或空间不足就扩容
if (ps->size == ps->capacity)
//第二种情况:capacity空间满了,扩容realloc,对已有的空间扩容
{
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity;
//如果=0给四。不是零增2倍
SLDataType* tmp = (SLDataType*)realloc(ps->a, newcapacity * sizeof(SLDataType));//不应给数据个数,应给字节个数
if (tmp == NULL)
{
printf("realloc fail\n");
exit(-1);
}
ps->a = tmp;
ps->capacity = newcapacity;
}
ps->a[ps->size] = x;
ps->size++;//空间足够
}
return -1:不可以,没有终止掉程序
exit(-1):结束掉程序,异常退出返回-1,正常返回0
动态顺序表:
//顺序表的动态存储
typedef struct SeqList
{
SLDataType* array;//指向动态开辟的数组
size_t size;//有效数据个数
size_t capacity;//容量空间的大小
}SeqList;
调试按Fn+F11
SeqList.c
void SeqListPrint(SL* ps)//把顺序表中的打印
{
for (int i = 0; i < ps->size; ++i)
{
printf("%d ", ps->a[i]);
}
printf("\n");
}
Test.c
SeqListPrint(&sl);
插入数据不用以后空间需要销毁。
//销毁顺序表
void SeqListDestory(SL* ps);
//销毁顺序表
void SeqListDestory(SL* ps);
{
free(ps->a);
ps->a = NULL;
ps->capacity = ps->size = 0;
}
//把空间还给系统
SeqListDestory(&SL);
继续写尾删,想把尾上的数据删除
typedef struct SeqList
{
SLDataType* a;
int size;//插入了两个数据
int capacity;//可以存几个数据
}SL;
把尾上的数置成零,再把size–
void SeqListPopBack(SL* ps)
{
//ps->a[ps->size - 1] = 0;//把数置成0
ps->size--;//原来是2,后来减到1.
}
size标识存了制了多少有效数据
SeqListPopBack(&sl);
SeqListPopBack(&sl);
//删除两个数据后再打印
SeqListPrint(&sl);
为防止删除的数据多于原本的数据个数
需加前提条件
void SeqListPopBack(SL* ps)
{
if (ps->size > 0)
{
ps->a[ps->size - 1] = 0;
ps->size--;//原来是2,后来减到1
}
}
粗暴的方式
#include <assert.h>//断言
void SeqListPopBack(SL* ps)
{
assert(ps->size > 0);
ps->size--;
}
在64行断言失败。