前言
前言
无论是考研也好工作也罢,数据结构一直是对计算机系同学们十分重要的科目(虽然我目前并不是。。),而由于学校学时的原因,数据结构这门课一直讲的很浅显,再加上学完之后没有怎么复习(简单工程性的项目里面其实并不需要用到多少数据结构),基本都忘光光了,所以我决定重刷数据结构,这个系列文章我会尽量坚持更下去的。
顺序表
顺序表是线性表的一种,又称为线性表的顺序表示,指的是用一组地址连续的存储单元一次存储线性表的数据元素,从定义上一个抽象的线性表主要包含三种元素:
- 存储空间首地址
- 当前长度
- 当前总共分配的存储容量
根据这三个元素我们可以构造出一个顺序表的抽象数据类型。
顺序表的实现
1.数据类型定义
#define LIST_INIT_SIZE 100 //线性表存储空间初始分配量
#define LIST_INCREMENT 10 //线性表存储空间分配增量
typedef struct{
int *start; //顺序表基址
int length; //顺序表长度
int listSize; //顺序表存储容量
}SqList;
2.功能实现,主要实现了插入,删除和两个顺序表的合并,注释很清楚,不多解释了
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include "SqListTest.h"
int initList(SqList *L);
int insertData(SqList *L, int index, int data);
int deleteData(SqList *L, int index, int *data);
SqList * unionList(SqList *La, SqList *Lb);
int main(void) {
SqList *list = (SqList *)malloc(sizeof(SqList));
if (initList(list))
{
int *temp = (int *)malloc(sizeof(int));
insertData(list, 1, 2);
insertData(list, 1, 3);
insertData(list, 3, 5);
deleteData(list, 3, temp);
for (int i = 0;i < list->length;i++)
{
printf("%d\n", list->start[i]);
}
printf("华丽分割线----------------------------------------------------------\n");
}
SqList *La = (SqList *)malloc(sizeof(SqList));
SqList *Lb = (SqList *)malloc(sizeof(SqList));
if (initList(La) && initList(Lb))
{
insertData(La, 1, 1);
insertData(La, 2, 6);
insertData(La, 3, 9);
insertData(Lb, 1, 2);
insertData(Lb, 2, 5);
insertData(Lb, 3, 7);
SqList *Lc = unionList(La, Lb);
for (int i = 0;i < Lc->length;i++)
{
printf("%d ", Lc->start[i]);
}
}
system("pause");
return 0;
}
//初始化顺序表
int initList(SqList *L) {
L->start = (int *)malloc(LIST_INIT_SIZE * sizeof(int));
if (!L->start)
{
printf("存储分配失败");
return 0;
}
L->length = 0;
L->listSize = LIST_INIT_SIZE;
return 1;
}
/************************************************************************/
/* 插入数值
/* L:顺序表
/* index:插入的位置
/* data:插入的数值
/************************************************************************/
int insertData(SqList *L, int index, int data) {
//若插入位置不合法,插入失败
if (index < 1 || index > L->length + 1)
{
return 0;
}
//若顺序表已满
if (L->length > L->listSize)
{
//新分配一块空间
int *newSpace = (int *)realloc(L->start, (L->listSize + LIST_INCREMENT) * sizeof(int));
if (!newSpace)
{
return 0; //存储分配失败
}
L->start = newSpace; //新基址
L->listSize += LIST_INCREMENT; //存储容量增加
}
int q;
//移动数值,将待插入的地址置空
for (q = L->length - 1;q >= index - 1;q--)
{
L->start[q + 1] = L->start[q];
}
L->start[index - 1] = data;
L->length++;
return 1;
}
/************************************************************************/
/* 删除 */
/************************************************************************/
int deleteData(SqList *L, int index, int *data) {
//若位置不合法
if (index < 1 || index > L->length)
{
return 0;
}
//记录被删除的数值
*data = L->start[index - 1];
//遍历覆盖
for (int i = index - 1;i < L->length - 1;i++)
{
L->start[i] = L->start[i + 1];
}
//更新表的长度
L->length--;
return 1;
}
/************************************************************************/
/* 两个递增顺序表的合并 */
/************************************************************************/
SqList * unionList(SqList *La, SqList *Lb) {
//pa,,pb用于记录两个顺序表的首地址
int *pa = La->start;
int *pb = Lb->start;
SqList *Lc = (SqList *)malloc(sizeof(SqList)); //创建Lc,并分配空间
if (!Lc)
{
return 0;
}
Lc->start = (int *)malloc((La->length + Lb->length) * sizeof(int));
//lc长度为两表长度之和
Lc->listSize = Lc->length = La->length + Lb->length;
if (!Lc->start)
{
return 0;
}
int *pc = Lc->start;
int *pa_last = La->start + La->length - 1;
int *pb_last = Lb->start + Lb->length - 1;
//当pa,pb都没有到达顺序表底部时,比较两者的值赋值给pc
while(pa <= pa_last && pb <= pb_last) {
if (*pa < *pb)
{
*pc++ = *pa++;
} else {
*pc++ = *pb++;
}
}
//pa,pb有一个到达底部直接将剩余值给LC
while(pa <= pa_last) {
*pc++ = *pa++;
}
while(pb <= pb_last) {
*pc++ = *pb++;
}
return Lc;
}
可以看到,顺序表的特点为,访问某个位置很容易,而在插入或者删除数据时,由于要进行大量的移位操作,所以效率很低那么可以得出结论:
- 如果需要使用的线性表需要做大量的查询访问工作,而很少对线性表进行插入删除工作,那么可以选择顺序表的数据结构