目录
线性表的定义与特点
线性表:由n(n>=0)个具有相同数据类型的数据元素构成的有限序列,记为(,
,
...,
),其中
(i为1到n)为表中元素n为表长,n=0时为空表。
生活中的线性表:如:一周中的七天(星期一,星期二,星期三,星期四,星期五,星期六,星期日)可以看成线性表;存放在MP3中的若干音乐歌曲目录也是线性表等。
对于非空的线性表或线性结构(即n!=0),其特点是:
1.有且仅有一个开始节点,它没有直接前驱(也叫头节点,首节点)
2.有且仅有一个终端节点,它没有直接后继(也叫尾节点)
3.中间的节点都有且仅有一个直接前驱和一个直接后继(所以这称为元素之间"一对一"的关系)
线性表的操作:
基本操作包括:
1.创建空的线性表并初始化
2.求线性表的长度
3.遍历线性表
4.插入一个新元素
5.删除一个元素
6.查找指定元素位置
7.清空线性表
其他操作:
1.线性表的拆分
2.两个线性表的合并等
线性表的顺序存储结构
顺序表是线性表的顺序存储表示的简称。
顺序表的定义:用一组连续的内存单元依次存储线性表的各个元素,也就是说,逻辑上相邻的元素,实际的物理存储空间也是连续的。(例子:一个班的学生,按学号排座位坐下,学号是连续的同时坐的位置也是连续的。)
数组类型的存储模式:
基本操作包括:
1.创建空的线性表并初始化
cpp
#include<stdio.h>
#define MAXSIZE 100
typedef int ElemType;
//顺序表-存储结构
typedef struct {//typedef用来修改结构体的名称
ElemType data[MAXSIZE];//声明一个长度为100,整数类型的数组,数组默认会自动初始化为0
int length;//记录当前顺序表中的元素个数
}SeqList;
//顺序表-初始化
void initList(SeqList* L) {
L->length = 0;//初始化新创建的结构体的元素个数为0
}
实现
int main() {
//创建一个结构体类型的变量
SeqList list;
//初始化,调用初始化函数
initList(&list);
printf("目前顺序表长度为%d\n", list.length);//目前顺序表长度为0
printf("目前占用内存%zu字节\n", sizeof(list.data));//目前占用内存400字节
return 0;
}
2.求线性表的长度
cpp
//调用顺序表中的length查看长度
3.遍历线性表
cpp
void ListElem(SeqList* L) {
for (int i = 0; i < L->length; i++) {
printf("%d ", L->data[i]);
}
printf("\n");
}
4.插入一个新元素(三种方法)
cpp
//顺序表-插入元素
//1.尾插法
int appendTail(SeqList* L, ElemType e) {//传入顺序表和要追加的内容
//判断顺序表是否可以再追加元素
if (L->length >= MAXSIZE) {
printf("顺序表已满!");
return 0;
}
//可以添加
L->data[L->length] = e;//顺序表的第一个元素是从1开始,数组的第一个元素是从0开始
L->length++;
return 1;
}
//2.头插法
int appendHead(SeqList* L, ElemType e) {//传入顺序表和要追加的内容
//判断顺序表是否可以再追加元素
if (L->length >= MAXSIZE) {
printf("顺序表已满!");
return 0;
}
//可以添加,将后面的元素都向后移一位空出第一个元素的位置
for (int i = L->length - 1; i >= 0; i--) {
L->data[i + 1] = L->data[i];//将前一个元素的值赋值给后一个元素的值
}
//此时第一个元素的位置已经空出,可以进行插入元素操作
L->data[0] = e;
L->length++;
return 1;
}
//3.在顺序表中指定位置插入元素
int appendPos(SeqList* L, int pos, ElemType e) {//传入顺序表,要插入元素的位置和要追加的内容
//判断顺序表是否可以再插入元素
if (L->length >= MAXSIZE) {
printf("顺序表已满!");
return 0;
}
//判断插入的位置是否合理
if (pos < 1 || pos > L->length) {//顺序表的第一个元素是从1开始,数组的第一个元素是从0开始
printf("你插入元素位置有误!");
return 0;
}
//若可以插入元素,将数组中pos-1(包含)之后的所有元素向后移动一个位置
//使用for循环
for (int i = L->length - 1; i >= pos - 1; i--) {
L->data[i + 1] = L->data[i];
}
//插入元素
L->data[pos - 1] = e;
L->length++;
return 1;
}
5.删除一个元素
cpp
//顺序表-删除元素(并不是真正的删除而是将要删除的元素覆盖掉)
int deleteElem(SeqList* L, int pos, ElemType* e)//传入顺序表,要删除元素在顺序表中的位置,e用来存储删除的元素是什么
{
//判断顺序表是否为空
if (L->length == 0) {
printf("空表\n");
return 0;
}
//判断要删除元素的位置是否合理
if (pos < 1 || pos > L->length) {
printf("删除数据的位置有误!");
return 0;
}
//将要删除的元素覆盖,将后面的元素向前移动一个位置
*e = L->data[pos - 1];
for (int i = pos - 1; i < L->length; i++) {
L->data[i] = L->data[i + 1];
}
L->length--;
return 1;
}
6.查找指定元素位置
cpp
//顺序表-查找元素
int findElem(SeqList* L, ElemType e) {//传入顺序表和要查找的元素
//判断是否为空列表
if (L->length == 0) {
printf("空列表!");
return 0;
}
//遍历顺序表查找元素
for (int i = 0; i < L->length; i++) {
if (L->data[i] == e) {
return i + 1;
}
}
return 0;
}
7.清空线性表
cpp
//清空顺序表
SeqList* clearList(SeqList* L) {
//给顺序表中的length赋值为0
SeqList* P = L;
P->length = 0;
return P;
}
实现代码:
cpp
//实现
int main() {
SeqList list;
initList(&list);
//头插法添加元素
appendHead(&list, 89);
appendHead(&list, 85);
appendHead(&list, 56);
appendHead(&list, 8);
appendHead(&list, 9);
//遍历
ListElem(&list);//9 8 56 85 89
//在列表末尾添加元素
appendTail(&list, 99);
//遍历
ListElem(&list);//9 8 56 85 89 99
//在顺序表中第二个位置添加元素
appendPos(&list, 2, 66);
//遍历
ListElem(&list);//9 66 8 56 85 89 99
//删除顺序表中第五个元素
ElemType deldate;
deleteElem(&list, 5, &deldate);
printf("被删除元素为:%d\n", deldate);//被删除元素为:85
//遍历
ListElem(&list);//9 66 8 56 89 99
//查找元素89是否在顺序表中,如果在则返回在顺序表中的下标
printf("%d\n", findElem(&list, 89));//5
//清空顺序表
clearList(&list);
//遍历
ListElem(&list);//输出了一个空行
return 0;
}
动态内存分配存储模式:
1.创建空的线性表并初始化
cpp
#include<stdio.h>
#include<stdlib.h>
#define MAXSIZE 100
typedef int ElemType;
//顺序表动态分配内存及初始化
typedef struct {
ElemType* data;//不再是写好的数组,需要时用时创建,该指针指向堆内存中新开辟的连续空间
int length;
}SeqList;
//初始化
SeqList* initList() {
SeqList* L = (SeqList*)malloc(sizeof(SeqList));//开辟结构体那么大的空间存顺序表的结构体类型
L->data = (ElemType*)malloc(sizeof(ElemType) * MAXSIZE);//结构体中的data开辟MAXSIZE那么大的连续空间
L->length = 0;
return L;
}
int main() {
//创建一个结构体类型的变量
SeqList * list = initList();
//初始化,调用初始化函数
printf("--目前顺序表长度为%d\n", list->length);//--目前顺序表长度为0
//计算指针本身的大小(8字节)
printf("--目前占用内存%zu字节\n", sizeof(list->data));//--目前占用内存8字节 ,在 64 位系统中,任何指针类型的变量本身都占用 8 字节,所以无论指针指向多大的内存空间,sizeof(指针)的结果都是 8 字节
// 正确方式:计算指针指向的数组的实际大小
printf("--数组实际大小: %zu字节\n", sizeof(ElemType) * MAXSIZE);//--数组实际大小: 400字节
return 0;
}
其余步骤代码与上面的一样,这里不再赘述.
2.求线性表的长度
3.遍历线性表
4.插入一个新元素
5.删除一个元素
6.查找指定元素位置
7.清空线性表