知识框架:
![在这里插入图片描述](https://img-blog.csdnimg.cn/c66cb00ce4b8483e915f9436269c726f.png#pic_center)
一、线性表的基本概念
1.线性表的定义
线性表是具有相同数据类型的n个数据元素的有限序列,其中n为表长。
//静态分配存储空间
#define MaxSize 10
typedef struct {
int data[MaxSize];
int length;
}SqList;
//动态分配存储空间
typedef struct {
int *data;
int MaxSize, length;
}SeqList;
2.线性表的基本操作
InitList(&L):初始化表。构造一个空的线性表。
//静态初始化
void initList(SqList & L) {
for (int i = 0; i <MaxSize; i++)
L.data[i] = 0;
L.length = 0;
}
//动态分配内存空间初始化
void initList(SeqList& L) {
L.data = (int*)malloc(sizeof(int) * InitSize);
L.length = 0;
L.MaxSize = InitSize;
}
Length(L):求表长。返回线性表L的长度,即L中数据元素的个数
LocateElem(L,e):按值查找操作。在表L中查找具有给定关键值的元素
int LocatElem(SqList L,int e) {
for (int i = 0; i < L.length; i++)
if (L.data[i]==e)
return i + 1;
return 0;
}
GetElem(L,i):按位查找操作。获取表L中第i个位置的元素的值
int GetElem(SqList L, int i) {
return L.data[i - 1];
}
ListInsert(&L,i,e):插入操作。在表L中的第i个位置上插入指定元素e
bool ListInsert(SqList &L, int i, int e) {
if (i<1 || i>L.length + 1) {
printf("该位置不可以插入元素\n");
return false;
}
if (L.length >= MaxSize) {
printf("存储空间已满,不可以再插入元素\n");
return false;
}
for (int j=L.length;j>=i; i--)
L.data[j] = L.data[j - 1];
L.data[i - 1] = e;
L.length++;
return true;
}
ListDelete(&L,i,&e):删除操作。删除表中第i个位置的元素,并用e返回删除元素的值
bool ListDelete(SqList &L,int i,int & e) {
if (i<1 || i>L.length) {
printf("该位置没有元素可以删除\n");
return false;
}
e = L.data[i-1];
for (int j = i; j < L.length; i++)
L.data[j-1] = L.data[j];
L.length--;
return true;
}
PrintList(L):输出操作。按前后顺序输出线性表L的所有元素值。
Empty(L):判空操作。若L为空表,则返回true,否则返回false
DestroyList(&L):销毁操作。销毁线性表,并释放线性表L所占用的内存空间。
二、线性表的实现
1.顺序存储
顺序表的定义:线性表的顺序存储又称顺序表。 顺序表的特点是表中元素的逻辑顺序与物理顺序相同。
顺序表上基本操作的实现:
(1)插入操作
//插入函数 位置i插入数据 i及之后元素后移 1=<i<=length+1
bool InsertList(SqList& L, int i, int e)
{
if (i<1 || i>L.length + 1) //判断位置是否有效
{
printf("位置无效!!!\n");
return false;
}
if (L.length >= MaxSize)//判断存储空间是否已满
{
printf("当前存储空间已满!!!\n");
return false;
}
for (int j = L.length; j >= i; j--)//位置i及之后元素后移
{
L.data[j] = L.data[j - 1];
}
L.data[i - 1] = e;
L.length++;
for (int i = 0; i < L.length; i++)
cout << L.data[i] << " ";
return true;
}
(2)删除操作
//删除函数 删除位置i的元素 i之后的元素依次前移
bool ListDelete(SqList& L, int i)
{
if (i<1 || i>L.length)
{
printf("位置无效!!!\n");
return false;
}
for (int j = i; j <= L.length - 1; j++)//位置i之后元素依次前移覆盖
{
L.data[j - 1] = L.data[j];
}
L.length--;
for (int i = 0; i < L.length; i++)
cout << L.data[i] << " ";
return true;
}
(3)按值查找(顺序查找【注:也可以使用其他的查找方法】)
//查找函数 按位置从小到大查找第一个值等于e的元素 并返回位置
int LocateElem(SqList L, int e)
{
for (int i = 0; i < L.length; i++)//从低位置查找
if (L.data[i] == e)
return i + 1;
return 0;
}
总代码:
#include<iostream>
#include <malloc.h>
#define MaxSize 50
using namespace std;
typedef struct {
int data[MaxSize];
int length;
}SqList;
int InitList(SqList& L)
{
memset(L.data,0,sizeof(L));//初始化数据为0
L.length = 0; //初始化长度为0
return 0;
}
//创建顺序表函数 初始化前n个数据
bool CreateList(SqList& L, int n)
{
if (n<0 || n>MaxSize)false;//n非法
for (int i = 0; i< n; i++)
{
cin >> L.data[i];
L.length++;
}
cout << "顺序表如下所示:" << endl;
for (int i = 0; i < n; i++)
cout<<L.data[i]<<" ";
return true;
}
//插入函数 位置i插入数据 i及之后元素后移 1=<i<=length+1
bool InsertList(SqList& L, int i, int e)
{
if (i<1 || i>L.length + 1) //判断位置是否有效
{
printf("位置无效!!!\n");
return false;
}
if (L.length >= MaxSize)//判断存储空间是否已满
{
printf("当前存储空间已满!!!\n");
return false;
}
for (int j = L.length; j >= i; j--)//位置i及之后元素后移
{
L.data[j] = L.data[j - 1];
}
L.data[i - 1] = e;
L.length++;
for (int i = 0; i < L.length; i++)
cout << L.data[i] << " ";
return true;
}
//删除函数 删除位置i的元素 i之后的元素依次前移
bool ListDelete(SqList& L, int i)
{
if (i<1 || i>L.length)
{
printf("位置无效!!!\n");
return false;
}
for (int j = i; j <= L.length - 1; j++)//位置i之后元素依次前移覆盖
{
L.data[j - 1] = L.data[j];
}
L.length--;
for (int i = 0; i < L.length; i++)
cout << L.data[i] << " ";
return true;
}
//查找函数 按位置从小到大查找第一个值等于e的元素 并返回位置
int LocateElem(SqList L, int e)
{
for (int i = 0; i < L.length; i++)//从低位置查找
if (L.data[i] == e)
return i + 1;
return 0;
}
int main() {
SqList L; //定义顺序表L
InitList(L); //初始化顺序表
int n;
cout << "请输入数组的大小n:" << endl;
cin >> n;
cout << "请输入数组的元素:" << endl;
CreateList(L,n); //创造顺序表,即给顺序表中的元素赋值
cout << endl;
cout<< "插入操作:请输入位置i和数值e" <<endl;
int i, e;
cin >>i>>e;
InsertList(L, i, e);
cout << endl;
cout << "删除操作:请输入你要删除的位置i:" << endl;
int i1;
cin >> i1;
ListDelete(L, i1);
cout << endl;
cout << "查找操作:请输入你要查找的元素值e:" << endl;
int e1;
cin >> e1;
cout<<LocateElem(L, e1)<<endl;
return 0;
}
截图:
2.链式存储
(1)单链表
线性表的链式存储又称为单链表。
它是通过一组任意的存储单元来存储线性表中的数据元素。为了建立数据元素之间的线性关系,对每个链表结点,除存放元素自身的信息外,还需要存放一个指向其后继的指针。
引入头结点的两个优点:
①:由于第一个数据结点的位置被存放在头结点的指针域中,因此在链表的第一个位置上的操作和在表的其他位置上的操作一致,无需进行特殊处理
②:无论链表是否为空,其头指针都指向头结点的非空指针(空表中头结点的指针域为空),因此空表和非空表的处理也得到了统一。
1.采用头插法建立单链表:
//头插法建立单链表
LinkList List_HeadInsert(LinkList& L) {
int x;
L = (LinkList)malloc(sizeof(LNode));
L->next = NULL;
LNode* s;
scanf("%d", &x);
while (x != 9999) {
s = (LNode*)malloc(sizeof(LNode));
s->data = x;
s->next = L->next;
L->next = s;
scanf("%d", &x);
}
return L;
}
2.采用尾插法建立单链表:
//尾插法建立单链表
LinkList List_TailInsert(LinkList& L) {
int x;
L = (LinkList)malloc(sizeof(LNode));
LNode* s, * r = L; //r为表尾指针
scanf("%d", &x);
while (x != 9999) {
s= (LNode *)malloc(sizeof(LNode));
s->data = x;
r->next = s;
r = s;
scanf("%d", &x);
}
r->next = NULL;
return L;
}
3.按序号查找结点值:
//按位查找(不带头结点)
LNode* GetElem(LinkList L, int i) {
LNode* p = L->next;
int j = 1;
if (i == 0)
return L;
if (i < 1)
return NULL;
while (p!=NULL||j<i)
{
p = p->next;
j++;
}
return p;
}
//按位查找(带头结点)
LNode* GetElem(LinkList L, int i) {
if (i < 0)
return NULL;
LNode* p = L;
int j = 0;
while (p != NULL || j < i)
{
p = p->next;
j++;
}
return p;
}
4.按值查找表结点
//按值查找
LNode* LocatElem(LinkList L,int e) {
LNode* p = L->next;
while (p!=NULL&& p->data!=e)
p = p->next;
return p;
}
5.插入结点操作
//插入操作(不带头结点)
bool ListInsert2(LinkList& L, int i, int e) {
if (i < 1)
return false;
if (i==1)
{
LNode *s = (LNode*)malloc(sizeof(LNode));
s->data = e;
s->next = L;
L = s;
return true;
}
LNode* p = L;
int j = 1;
while (p != NULL || j < i - 1)
{
p = p->next;
j++;
}
if (p == NULL)
return false;
LNode* s = (LNode*)malloc(sizeof(LNode));
s->data = e;
s->next = p->next;
p->next = s;
return true;
}
//尾插入(由于是在结点的后面插入元素,所以不需要考虑是否有头结点)
bool InsertNextNode(LNode* p, int e) {
if (p == NULL)
return false;
LNode* s = (LNode*)malloc(sizeof(LNode));
if (s == NULL)
return false;//内存分配失败
s->data = e;
s->next = p->next;
p->next = s;
return true;
}
//头插入(有头结点 虚假的前插入)
bool InsertPriorNode(LNode *p, int e) {
if (p == NULL)
return false;
LNode *s = (LNode*)malloc(sizeof(LNode));
if (s == NULL)
return false;//内存分配失败
s->next = p->next;
p->next = s;
s->data = p->data;
p->data = e;
return true;
}
6.删除结点操作
//删除操作
//带头结点删除
bool ListDelete1(LinkList &L,int i, int e) {
if (i<1)
return false;
LNode *p = L;
int j = 0;
while (p == NULL || j < i - 1) {
p = p->next;
j++;
}
if (p == NULL||p->next==NULL)
return false;
LNode* q = p->next;
e = q->data;
p->next = q->next->next;
free(q);
return true;
}
//不带头结点删除
bool ListDelete2(LinkList &L, int i, int e) {
if (i < 1)
return false;
LNode* p = L;
int j = 0;
while (p == NULL || j < i - 1) {
p = p->next;
j++;
}
if (p == NULL || p->next == NULL)
return false;
if (i == 1)
L = L->next;
return true;
}
7.求表长操作
(2)双链表
单链表结点中只有一个指向其后继的指针,使得单链表只能从头结点以此顺序往后遍历。
双链表有两个指针prior和next,分别指向其前驱结点和后继结点
1.双链表的插入操作
2.双链表的删除操作
(3)循环链表
1.循环单链表 循环单链表与单链表的区别是:表中的最后一个结点的指针不是NULL,而该为指向头结点,从而整个链表形成一个环。
2.循环双链表 循环双链表与双链表同循环单链表与单链表的关系
(4)静态链表(借助数组实现)
静态链表借助数组来描述线性表的链式存储结构,结点也有数据域data和指针域next,与其他链表中的指针不同的是,这里的指针是结点的相对地址(数组的下标),又称游标。和顺序表一样,静态链表也要预先分配好一块连续的内存空间。
//静态链表
#define MaxSize 10
typedef struct
{
int data;
int next;
}SLinkList[MaxSize];
void main() {
LinkList L;
InitList1(L);
}
需要数据结构、计算机网络、操作系统、计算机组成原理、c语言等等学习视频的!!!!!
微信公众号:小小小灵通 回复:王道 获取王道的教学视频、笔记、文档等提升课。(免费获取)