主要介绍线性表
由n(n>=0)个相同类型的元素组成的有序集合。
L=(a1,a2, ,ai-1,ai,ai+1, , an)
表中元素是有限的;
表中元素的数组类型都相同也即每一个元素占用相同大小的空间;
表中元素具有逻辑上的顺序性,在序列中各元素排列有其先后顺序。
初始化表;求表长;按值查找;按位查找;插入操作;删除操作;输出操作;判空操作;销毁操作。
线性表的顺序存储称为顺序表。
B. 实现方法:
B.1 静态分配:
//伪代码,只是代码中的重要部分,不可执行
#define MaxSize 50//定义线性表长度
typedef int ElemType;//重定义int型为ElemType
typedef struct {
ElemType data[MaxSize];//定义顺序表元素
int length;//定义顺序表当前长度
}SqList;//定顺序表型变量SqList
B.2 动态分配:
//伪代码,只是代码中的重要部分,不可执行
#define InitSize 100//定义线性表长度
typedef int ElemType;//重定义int型为ElemType
typedef struct {
ElemType *data;//指示动态分配数组的指针
int MaxSize ,length;//数组的最大容量与当前长度
}SqList;//定顺序表型变量SqList
//C的初试动态分配语句:
L.data=(ElemType*)malloc(sizeof(ElemType)*InitSize);
//C++的初试动态分配语句:
L.data=new ElemType[InitSize];
A. 插入操作
A. 1 核心代码
//伪代码,只是代码中的重要部分,不可执行
if (i<1 || i>L.length + 1)//判断插入的位置是否合法
return false;
if (L.length>MaxSize)//判断插入的位置是否超出存储空间
return false;
for (int j = L.length; j >= i; j--)//移动顺序表中的元素,依次向后移动
L.data[j] = L.data[j - 1];
L.data[i-1] = e;//数组下标从0开始,插入第一个位置,访问的下标为0
L.length++;
A. 2实战代码
#include
#include
//1.静态分配(结构体声明)
#define MaxSize 50
typedef int ElemType;//顺序表中元素的类型
typedef struct {
ElemType data[MaxSize];//定义数组用来存储元素
int length;//当前顺序表中元素个数
}Sqlist;
//2.表中插入元素
bool ListInsert(Sqlist& L, int i, ElemType e)
{
//插入不合理的处理
if (i<1 || i>L.length + 1)//判断插入的位置是否合法
return false;
if (L.length>MaxSize)//判断插入的位置是否超出存储空间
return false;
for (int j = L.length; j >= i; j--)//移动顺序表中的元素,依次向后移动
L.data[j] = L.data[j - 1];
L.data[i-1] = e;//数组下标从0开始,插入第一个位置,访问的下标为0
L.length++;
return true;
}
//3.输出表
void PrintList(Sqlist L)
{
for (int i = 0; i < L.length; i++)
printf("L.data[%d]=%d\n",i, L.data[i]);
}
//4.主函数
int main()
{
Sqlist L;//定义顺序表
bool ret;//查看返回值,True或False
//手动在顺序表中赋值
L.data[0] = 1;
L.data[1] = 2;
L.data[2] = 3;
L.length = 3;//一共三个元素
ret = ListInsert(L, 2, 60);//往第二个位置插入60
if (ret)
{
printf("插入成功\n");
PrintList(L);//输出表
}
else {
printf("插入失败\n");
}
return 0;
}
B. 删除操作
B. 1 核心代码
//伪代码,只是代码中的重要部分,不可执行
if (i<1 || i>L.length + 1)//判断插入的位置是否合法
return false;
del=L.date[i-1];//将被删除的元素赋给del
for (int j = i; j<L.length; j++)//将删除位置后的元素依次向前移动
L.data[j-1] = L.data[j];
L.length--;
B. 2 实战代码
#include
#include
/*
//1.2动态分配
#define InitSize 50
typedef struct {
ElemType data[MaxSize];
int length;//当前顺序表中元素个数
}Sqlist;
*/
//1.1静态分配(结构体声明)
#define MaxSize 50
typedef int ElemType;//顺序表中元素的类型
typedef struct {
ElemType data[MaxSize];//定义数组用来存储元素
int length;//当前顺序表中元素个数
}Sqlist;
//2.输出表
void PrintList(Sqlist L)
{
for (int i = 0; i < L.length; i++)
printf("L.data[%d]=%d\n", i, L.data[i]);
}
//4.1表中删除元素
bool ListDelete(Sqlist& L, int i, ElemType e)
{
//插入不合理的处理
if (i<1 || i>L.length + 1)//判断删除的位置是否合法
return false;
if (L.length ==0)//顺序表中没有元素,无需删除
return false;
e = L.data[i - 1];//获取顺序表中要删除的元素赋值给e
for (int j =i; j< L.length; j++)
L.data[j-1] = L.data[j];
L.length--;
return true;
}
int main()//
{
//1.3顺序表赋值
Sqlist L;//定义顺序表
//手动在顺序表中赋值
L.data[0] = 1;
L.data[1] = 2;
L.data[2] = 3;
L.length = 3;//一共三个元素
//4.2删除操作部分
bool ret_delete;//查看返回值,True或False
ElemType del=NULL;
ret_delete = ListDelete(L, 2, del);//删除第二个位置的元素
if (ret_delete)
{
printf("删除成功\n");
printf("删除元素为%d\n",del);
PrintList(L);
}
else {
printf("删除失败\n");
}
return 0;
}
C. 查询操作
C. 1 核心代码
//伪代码,只是代码中的重要部分,不可执行
for (int i = 0; i < L.length; i++)
if (L.data[i]==e)
return i+1;//数组从0开始,顺序表从1开始
B. 2 实战代码
#include
#include
//1.1静态分配(结构体声明)
#define MaxSize 50
typedef int ElemType;//顺序表中元素的类型
typedef struct {
ElemType data[MaxSize];//定义数组用来存储元素
int length;//当前顺序表中元素个数
}Sqlist;
//2.输出表
void PrintList(Sqlist L)
{
for (int i = 0; i < L.length; i++)
printf("L.data[%d]=%d\n", i, L.data[i]);
}
//5.1按值查询
int LocateElem(Sqlist& L,ElemType e)
{
for (int i = 0; i < L.length; i++)
if (L.data[i]==e)
return i+1;//数组从0开始,顺序表从1开始
return 0;
}
int main()//
{
//1.3顺序表赋值
Sqlist L;//定义顺序表
//手动在顺序表中赋值
L.data[0] = 1;
L.data[1] = 2;
L.data[2] = 3;
L.length = 3;//一共三个元素
//5.2 查询操作部分
bool ret_search;//查看返回值,True或False
ret_search = LocateElem(L,2);//删除第二个位置的元素
if (ret_search)
{
printf("查询成功\n");
printf("元素位置为%d\n", ret_search);//bool与int型可以相互转换
}
else {
printf("查询失败\n");
}
return 0;
}
F. 修改操作
在这里插入代码片
A. 优点:
可以随机存取(根据表头元素地址和元素序号)表中任意一个元素;
存储密度高,每个节点只存储数据元素。
B. 缺点:
插入与删除操作需要移动大量的元素;
线性表变化较大时,难以确定存储空间的容量;
存储分配需要一整段连续的存储空间,不够灵活。
A. 定义:线性表的链式表存储为单链表
头指针:链表中第一个节点的存储位置,用来标识单链表。
头结点:在单链表第一个节点之前附加一个节点,为了操作上的方便。
若链表有头结点,则头指针永远指向头结点,不论链表是否为空,头指针均不为空,头指针是链表的必须元素,他标识一个链表。
头结点是为了操作的方便而设立的,其数据域一般为空,或者存放链表的长度,有头结点后,对在第一个节点前插入和删除第一个节点的操作就统一了,不需要频繁重置指针,但头结点不是必须的。
B. 核心代码
typedef struct LNode//单链表结构点类型
{
ElemType data;//数字域
stryct LNode *next;//指针域
}LNode,*LinkList;
A. 头插法建立单链表
//伪代码,只是代码中的重要部分,不可执行
LinkList CreatList1(LinkList& L)//list_head_insert
{
LNode* s;
int x;
L = (LinkList)malloc(sizeof(LNode));//带头结点的链表
L->next = NULL;//L->data里面没用放东西
scanf("%d", &x);//从标准输入读取数据
while (x != 9999) {
s = (LNode*)malloc(sizeof(LNode));//申请一个空间,强制类型转换
s->data = x;//
s->next = L->next;//让新节点的next指针指向链表的第一个元素
L->next = s;//让s作为第一个元素
scanf("%d", &x);//读取标准输入
}
return 0;
}
B. 尾插法建立单链表
//伪代码,只是代码中的重要部分,不可执行
LinkList CreatList2(LinkList& L)//list_head_insert
{
int x;
L = (LinkList)malloc(sizeof(LNode));//带头结点的链表
LNode* s, * r = L;//LinkList s,r;r代表表尾节点
scanf("%d", &x);//从标准输入读取数据
while (x != 9999) {
s = (LNode*)malloc(sizeof(LNode));//申请一个空间,强制类型转换
s->data = x;//
r->next = s;//让尾部节点指向新节点
r = s;//r指向新的表尾节点
scanf("%d", &x);//读取标准输入
}
r->next =NULL;//尾部节点的next指针赋值NULL
return 0;
}
C. 按序号查询
//伪代码,只是代码中的重要部分,不可执行
LNode* GetElem(LinkList L, int i)
{
int j = 1;
LNode* p = L->next;//让P指向第一个节点
if (i == 0)
return L;
if (i < 1)
return NULL;
while (p && j < i)
{
p = p->next;
j++;
}
return p;
}
D. 按值查找操作
LinkList LocateElem(LinkList L, ElemType i)
{
LinkList p = L->next;
while (p != NULL && p->data != i)
{
p = p->next;
}
return p;
}
E.链表的删除
bool ListDelete(LinkList L, int i)
{
LinkList p = GetElem(L, i-1);
if (NULL == p)
{
return false;
}
LinkList q = p->next;
p->next = q->next;
free(q);
q = NULL;//避免野指针
return true;
}
F.链表的插入
//5.1链表的插入
bool ListFrontInsert(LinkList L, int i, ElemType e)
{
LinkList p = GetElem(L, i - 1);
if (NULL == p)
{
return false;
}
LinkList s = (LNode*)malloc(sizeof(LNode));
s->data = e;
s->next = p->next;
p->next = s;
return true;
}
G.实战代码
#define _CRT_SECURE_NO_WARNINGS
#include
#include
//0.0定义链表
typedef int ElemType;
typedef struct LNode {
ElemType data;
struct LNode* next;//指向下一个节点
}LNode,*LinkList;
//1.1头插法新建链表
LinkList CreatList1(LinkList& L)//list_head_insert
{
LNode* s;
int x;
L = (LinkList)malloc(sizeof(LNode));//带头结点的链表
L->next = NULL;//L->data里面没用放东西
scanf("%d", &x);//从标准输入读取数据
while (x != 9999) {
s = (LNode*)malloc(sizeof(LNode));//申请一个空间,强制类型转换
s->data = x;//
s->next = L->next;//让新节点的next指针指向链表的第一个元素
L->next = s;//让s作为第一个元素
scanf("%d", &x);//读取标准输入
}
return 0;
}
//1.2尾插法新建链表
LinkList CreatList2(LinkList& L)//list_head_insert
{
int x;
L = (LinkList)malloc(sizeof(LNode));//带头结点的链表
LNode* s, * r = L;//LinkList s,r;r代表表尾节点
scanf("%d", &x);//从标准输入读取数据
while (x != 9999) {
s = (LNode*)malloc(sizeof(LNode));//申请一个空间,强制类型转换
s->data = x;//
r->next = s;//让尾部节点指向新节点
r = s;//r指向新的表尾节点
scanf("%d", &x);//读取标准输入
}
r->next =NULL;//尾部节点的next指针赋值NULL
return 0;
}
//2.1打印链表
void PrintList(LinkList L)
{
L = L->next;
while (L!= NULL)
{
printf("%3d", L->data);//打印当前节点数据
L = L->next;
}
printf("\n");
};
//3.1链表的按序号查找
LNode* GetElem(LinkList L, int i)
{
int j = 1;
LNode* p = L->next;//让P指向第一个节点
if (i == 0)
return L;
if (i < 1)
return NULL;
while (p && j < i)
{
p = p->next;
j++;
}
return p;
}
//3.2链表的按值查找
LinkList LocateElem(LinkList L, ElemType i)
{
LinkList p = L->next;
while (p != NULL && p->data != i)
{
p = p->next;
}
return p;
}
//4.1链表的删除
bool ListDelete(LinkList L, int i)
{
LinkList p = GetElem(L, i-1);
if (NULL == p)
{
return false;
}
LinkList q = p->next;
p->next = q->next;
free(q);
q = NULL;//避免野指针
return true;
}
//5.1链表的插入
bool ListFrontInsert(LinkList L, int i, ElemType e)
{
LinkList p = GetElem(L, i - 1);
if (NULL == p)
{
return false;
}
LinkList s = (LNode*)malloc(sizeof(LNode));
s->data = e;
s->next = p->next;
p->next = s;
return true;
}
int main()
{
//1.3链表的建立
LinkList L;//链表头,是结构体指针类型
CreatList1(L);//输入数据可以为3 4 5 6 7 9999,头插法新建列表
//CreatList2(L);//输入数据可以为3 4 5 6 7 9999,尾插法新建列表
//2.2打印链表
//PrintList(L);
//3.3链表的按序号查找
//LinkList search;//用来存储拿到的某一个节点
//search = GetElem(L, 6);
//if(search!=NULL)
//{
// printf("按序号查找成功\n");
// printf("%d\n", search->data);
//}
//3.4链表的按值查找
//LinkList search;//用来存储拿到的某一个节点
//search = LocateElem(L,4);//按值查询
//if (search != NULL)
//{
// printf("按序号查找成功\n");
// printf("%d\n", search->data);
//}
//4.2链表的删除
//ListDelete(L, 3);
//5.2链表的插入
//ListFrontInsert(L, 2, 88);
PrintList(L);
}
A. 定义
//核心代码
typedef struct DNode {//双链表节点类型
ElemType data;//数据域
struct DNode* prior;//前驱指针
struct DNode* next;//后继指针
}DNode, * DLinkList;
//伪代码,表示主要功能
s->next = p->next;//表示上图第1步
p->next->prior = s;//表示上图第2步
s->prior = p;//表示上图第3步
p->next = s;//表示上图第4步
p->next = q->next;//表示上图第1步
q->next->prior = p;//表示上图第2步
free(q);//表示上图第3步
D.实战代码
#define _CRT_SECURE_NO_WARNINGS
#include
#include
//0双向链表的定义
typedef int ElemType;
typedef struct DNode {//双链表节点类型
ElemType data;//数据域
struct DNode* prior;//前驱指针
struct DNode* next;//后继指针
}DNode, * DLinkList;
//4按序号查找
DNode* GetElem(DLinkList DL, int i)
{
int j = 1;
DNode* p = DL->next;//让P指向第一个节点
if (i == 0)
return DL;
if (i < 1)
return NULL;
while (p && j < i)
{
p = p->next;
j++;
}
return p;
}
//1.1头插法插入操作
DLinkList DList_head_insert(DLinkList &DL)
{
DNode *s;int x;
DL = (DLinkList)malloc(sizeof(DNode));//带头结点的链表
DL->next = NULL;
DL->prior = NULL;
scanf("%d", &x);//从标准输入读取数据,//3 4 5 6 7 9999
while (x != 9999) {
s = (DNode*)malloc(sizeof(DNode));//申请一个空间,强制类型转换
s->data = x;
s->next = DL->next;
if (DL->next!= NULL)
{
DL->next->prior = s;
}
s->prior = DL;
DL->next = s;
scanf("%d", &x);
}
return 0;
}
//1.2尾插法插入操作
DLinkList DList_tail_insert(DLinkList &DL)
{
int x;
DL = (DLinkList)malloc(sizeof(DNode));//带头结点的链表
DNode* s, * r = DL;//r代表尾部指针,等价于DNode* s;DNode** r = DL;
DL->prior = NULL;
scanf("%d", &x);//从标准输入读取数据,//3 4 5 6 7 9999
while (x != 9999) {
s = (DNode*)malloc(sizeof(DNode));//申请一个空间,强制类型转换
s->data = x;
r->next = s;
s->prior = r;
r = s;//r指向新的表尾节点
scanf("%d", &x);
}
r->next = NULL;//尾结点指针置空
return 0;
}
//1.3新节点插入操作
bool DList_Front_insert(DLinkList& DL,int i,ElemType e)
{
DLinkList p = GetElem(DL,i-1);
if (NULL == p)
{
return false;
}
DLinkList s = (DLinkList)malloc(sizeof(DNode));//带头结点的链表
s->data =e;
s->next = p->next;
s->next->prior = s;
p->next = s;
return true;
}
//2输出双链表
void PrintDList(DLinkList DL)
{
DL = DL->next;
while (DL != NULL)
{
printf("%3d", DL->data);//打印当前节点数据
DL = DL->next;
}
printf("\n");
};
//3删除操作
bool DListDelete(DLinkList& DL, int i)
{
DLinkList p = GetElem(DL, i - 1);
DLinkList q = p->next;
if (NULL == p)
{
return false;
}
if(NULL==q)
{
return false;
}
q->next->prior = p;
p->next = q->next;//表示上图第1步
free(q);//释放节点对应空间
return true;
}
int main()
{
DLinkList DL;
//1.1头插法插入操作
//DList_head_insert(DL);//list_head_insert
//1.2尾插法插入操作
DList_tail_insert(DL);//3 4 5 6 7 9999
//1.3新节点插入操作
//DList_Front_insert(DL,2,45);//3 4 5 6 7 9999
//2输出双链表
PrintDList(DL);
3删除操作
DListDelete(DL, 2);
PrintDList(DL);
//4按序号查找
/*DLinkList search_1;
search_1 = GetElem(DL,2);
if(search_1!=NULL)
{
printf("按序号查找成功\n");
printf("%d\n",search_1->data);
}*/
return 0;
}
A. 循环单链表
循环链表与单链表的区别:表中最后一个结点的next指针不是NULL,而是指向头结点,从而整个链条形成一个环。
B. 循环双链表
循环双链表与双链表的区别:表中最后一个结点的next指针不是NULL,而是指向头结点;表中第一个结点的prior指针不是NULL,而是指向尾结点。
静态链表是借助数组来描述线性表的链式存储结构,且结构类型如下:
#define Maxsize 50
typedef struct{
ElemType data;
int next;
}SLinkList[Maxsize];
提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。