目录
介绍:
线性表是相同数据的集合,类似于数组,但比数组多了增删改查的功能,这些功能需要我们自己写,线性表分顺序表和链表
- 顺序表:用一组连续的内存单元存储线性表的各种数据,逻辑上相邻的元素,实际上物理存储空间也是连续的,虽然叫顺序表,但在我们使用时还是用数组用来存储数据
- **链表:**链表是用任意存储单元存储链表元素,链表数据的内存大概率不是连在一起的 ,链表中的每个节点不仅包含存储的信息,还包含上一节点和下一节点的地址,头节点不存数据
顺序表
创建顺序表
length:这是顺序表的元素个数,不是元素下标,这里的typedef struct定义的是一个没有名字的结构体,到下面的SeqList才是给这个结构体取别名
//让程序更灵活
typedef int ELemtype;//data数组的大小
#define MAXSIZE 100typedef struct
{
ELemtype data[MAXSIZE];
//表示顺序表中有几个元素
int length;
}SeqList;
初始化顺序表
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
typedef int ELemtype;
#define MAXSIZE 100
typedef struct
{
ELemtype data[MAXSIZE];
int length;
}SeqList;
void SeqList_Init(SeqList* L)
{
L->length = 0;
}
在顺序表中添加元素
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
typedef int ELemtype;
#define MAXSIZE 100
//创建顺序表
typedef struct
{
ELemtype data[MAXSIZE];
int length;
}SeqList;
//初始化顺序表
void SeqList_Init(SeqList* L)
{
L->length = 0;
}
//在顺序表中添加元素
int SeqList_Add(SeqList* L,ELemtype e)
{
if (L->length >= MAXSIZE)
{
printf("顺序表已满");
return 0;
}
else
{
L->data[L->length] = e;
L->length++;
return 0;
}
}
void main(void)
{
//创建顺序表1
SeqList list_1;
//初始化顺序表
SeqList_Init(&list_1);
//在顺序表中添加元素
SeqList_Add(&list_1, 2);
printf("%d\n", list_1.data[list_1.length-1]);
}
遍历顺序表
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
typedef int ELemtype;
#define MAXSIZE 100
//创建顺序表
typedef struct
{
ELemtype data[MAXSIZE];
int length;
}SeqList;
//初始化顺序表
void SeqList_Init(SeqList* L)
{
L->length = 0;
}
//在顺序表中添加元素
int SeqList_Add(SeqList* L,ELemtype e)
{
if (L->length >= MAXSIZE)
{
printf("顺序表已满");
return 0;
}
else
{
L->data[L->length] = e;
L->length++;
return 0;
}
}
//遍历顺序表
void SeqList_Elem(SeqList* L)
{
if (L->length == 0)
{
printf("顺序表无元素\n");
}
else
{
for (int i = 0;i < L->length;i++)
{
printf("%d\n", L->data[i]);
}
}
}
void main(void)
{
//创建顺序表1
SeqList list_1;
//初始化顺序表
SeqList_Init(&list_1);
//在顺序表中添加元素
SeqList_Add(&list_1, 1);
SeqList_Add(&list_1, 2);
SeqList_Add(&list_1, 3);
//遍历顺序表
SeqList_Elem(&list_1);
}
插入一个元素
插入一个元素逻辑,
**插入位置:**不能大于整个顺序表,不能在0位置插入,插入位置不能超过顺序表总元素的位置,如顺序表有3个元素,不能在插在第5个元素
逻辑:在插入元素后面的元素都要往后移一位,直到移到插入位置没有元素为止
**for (int i = L->length-1;i >=pos-1;i--),**这里length-1,是Length位置数据的下标,pos-1,也是代表pos位置的数据的下标
L->data[pos-1] = e;,表示将e赋值给pos位置
L->length++;,插入一个数据,顺序表数据增加一个
#include "stdio.h"
#include "stdlib.h"
#include "string.h"typedef int ELemtype;
#define MAXSIZE 100
//创建顺序表
typedef struct
{
ELemtype data[MAXSIZE];
int length;
}SeqList;//初始化顺序表
void SeqList_Init(SeqList* L)
{
L->length = 0;
}//在顺序表中添加元素
int SeqList_Add(SeqList* L,ELemtype e)
{
if (L->length >= MAXSIZE)
{
printf("顺序表已满");
return 0;
}
else
{
L->data[L->length] = e;
L->length++;
return 0;
}
}//遍历顺序表
void SeqList_Elem(SeqList* L)
{
if (L->length == 0)
{
printf("顺序表无元素\n");
}
else
{
for (int i = 0;i < L->length;i++)
{
printf("%d\n", L->data[i]);
}
}
}//插入一个元素
int InSertElem(SeqList* L, int pos, ELemtype e)
{
if (L->length >= MAXSIZE)
{
printf("顺序表已满\n");
return 0;
}
if (pos > MAXSIZE)
{
printf("顺序表没有怎么长\n");
return 0;
}
if (pos > L->length||pos<1)
{
printf("插错位置了\n");
return 0;
}
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;
}void main(void)
{
//创建顺序表1
SeqList list_1;
//初始化顺序表 SeqList_Init(&list_1); //在顺序表中添加元素 SeqList_Add(&list_1, 1); SeqList_Add(&list_1, 2); SeqList_Add(&list_1, 3); //在1位置插入5 InSertElem(&list_1, 1, 5); //遍历顺序表 SeqList_Elem(&list_1);}
删除一个元素
删除一个元素实际上是覆盖,假设想删除位置2的元素,你将位置3元素的值赋值给位置2,再将位置4的元素赋值给位置3,依次赋值,到最后一个元素赋值完,length--就行了
元素的增删改查实际就是元素覆盖,
#include "stdio.h" #include "stdlib.h" #include "string.h" typedef int ELemtype; #define MAXSIZE 100 //创建顺序表 typedef struct { ELemtype data[MAXSIZE]; int length; }SeqList; //初始化顺序表 void SeqList_Init(SeqList* L) { L->length = 0; } //在顺序表中添加元素 int SeqList_Add(SeqList* L,ELemtype e) { if (L->length >= MAXSIZE) { printf("顺序表已满"); return 0; } else { L->data[L->length] = e; L->length++; return 0; } } //遍历顺序表 void SeqList_Elem(SeqList* L) { if (L->length == 0) { printf("顺序表无元素\n"); } else { for (int i = 0;i < L->length;i++) { printf("%d\n", L->data[i]); } } } //插入一个元素 int InSertElem(SeqList* L, int pos, ELemtype e) { if (L->length >= MAXSIZE) { printf("顺序表已满\n"); return 0; } if (pos > MAXSIZE) { printf("顺序表没有怎么长\n"); return 0; } if (pos > L->length||pos<1) { printf("插错位置了\n"); return 0; } 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; } //删除一个元素 int DeleteElem(SeqList* L, int pos) { if (pos < L->length || pos >= 1) { for (int i = pos - 1;i <= L->length - 1;i++) { L->data[i] = L->data[i + 1]; } L->length--; return 1; } } void main(void) { //创建顺序表1 SeqList list_1; //初始化顺序表 SeqList_Init(&list_1); //在顺序表中添加元素 SeqList_Add(&list_1, 1); SeqList_Add(&list_1, 2); SeqList_Add(&list_1, 3); InSertElem(&list_1, 1, 5); DeleteElem(&list_1, 2); //遍历顺序表 SeqList_Elem(&list_1); }
查找数据
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
typedef int ELemtype;
#define MAXSIZE 100
//创建顺序表
typedef struct
{
ELemtype data[MAXSIZE];
int length;
}SeqList;
//初始化顺序表
void SeqList_Init(SeqList* L)
{
L->length = 0;
}
//在顺序表中添加元素
int SeqList_Add(SeqList* L,ELemtype e)
{
if (L->length >= MAXSIZE)
{
printf("顺序表已满");
return 0;
}
else
{
L->data[L->length] = e;
L->length++;
return 0;
}
}
//遍历顺序表
void SeqList_Elem(SeqList* L)
{
if (L->length == 0)
{
printf("顺序表无元素\n");
}
else
{
for (int i = 0;i < L->length;i++)
{
printf("%d\n", L->data[i]);
}
}
}
//插入一个元素
int InSertElem(SeqList* L, int pos, ELemtype e)
{
if (L->length >= MAXSIZE)
{
printf("顺序表已满\n");
return 0;
}
if (pos > MAXSIZE)
{
printf("顺序表没有怎么长\n");
return 0;
}
if (pos > L->length||pos<1)
{
printf("插错位置了\n");
return 0;
}
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;
}
//删除一个元素
int DeleteElem(SeqList* L, int pos)
{
if (pos < L->length || pos >= 1)
{
for (int i = pos - 1;i <= L->length - 1;i++)
{
L->data[i] = L->data[i + 1];
}
L->length--;
return 1;
}
}
//查找数据,看看顺序表中又名没有这个数据
int FindElem(SeqList* L, ELemtype e)
{
for (int i = 0;i <= L->length;i++)
{
if (L->data[i] == e)
{
printf("有这个数据,位置在%d\n",i+1);
return 1;
}
}
printf("没有\n");
return 0;
}
void main(void)
{
//创建顺序表1
SeqList list_1;
//初始化顺序表
SeqList_Init(&list_1);
//在顺序表中添加元素
SeqList_Add(&list_1, 1);
SeqList_Add(&list_1, 2);
SeqList_Add(&list_1, 3);
InSertElem(&list_1, 1, 5);
DeleteElem(&list_1, 2);
//遍历顺序表
SeqList_Elem(&list_1);
FindElem(&list_1, 5);
}
用堆内存分配内存
这里用malloc开辟结构体和数组,让结构体和数组在推内存中创建,节省栈内存空间,这时List_1,就是地址要注意 ,传参时就不用取地址符了
#include "stdio.h" #include "stdlib.h" #include "string.h" typedef int ELemtype; #define MAXSIZE 100 //创建顺序表 typedef struct { ELemtype *data; int length; }SeqList; //用推内存初始化顺序表 SeqList* SeqList_Init() { SeqList* L = (SeqList*)malloc(sizeof(SeqList)); L->data = (ELemtype*)malloc(sizeof(ELemtype) * MAXSIZE); L->length = 0; return L; } //在顺序表中添加元素 int SeqList_Add(SeqList* L,ELemtype e) { if (L->length >= MAXSIZE) { printf("顺序表已满"); return 0; } else { L->data[L->length] = e; L->length++; return 0; } } //遍历顺序表 void SeqList_Elem(SeqList* L) { if (L->length == 0) { printf("顺序表无元素\n"); } else { for (int i = 0;i < L->length;i++) { printf("%d\n", L->data[i]); } } } //插入一个元素 int InSertElem(SeqList* L, int pos, ELemtype e) { if (L->length >= MAXSIZE) { printf("顺序表已满\n"); return 0; } if (pos > MAXSIZE) { printf("顺序表没有怎么长\n"); return 0; } if (pos > L->length||pos<1) { printf("插错位置了\n"); return 0; } 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; } //删除一个元素 int DeleteElem(SeqList* L, int pos) { if (pos < L->length || pos >= 1) { for (int i = pos - 1;i <= L->length - 1;i++) { L->data[i] = L->data[i + 1]; } L->length--; return 1; } } //查找数据,看看顺序表中又名没有这个数据 int FindElem(SeqList* L, ELemtype e) { for (int i = 0;i <= L->length;i++) { if (L->data[i] == e) { printf("有这个数据,位置在%d\n",i+1); return 1; } } printf("没有\n"); return 0; } void main(void) { //创建顺序表1 SeqList *list_1; //初始化顺序表 list_1=SeqList_Init(); //在顺序表中添加元素 SeqList_Add(list_1, 1); SeqList_Add(list_1, 2); SeqList_Add(list_1, 3); InSertElem(list_1, 1, 5); //DeleteElem(list_1, 2); //遍历顺序表 SeqList_Elem(list_1); FindElem(list_1, 2); }
链表
单链表
创建链表
typedef struct node :表示定义一个名为node的结构体,在下面把这个结构体取别名为Node,
struct node* next :这里表示定义一个类型为node的指针
#include "stdio.h" typedef int ElemType; typedef struct node { struct node* next ; ElemType data; }Node;
初始化链表
初始化链表就是创建头节点,将头节点在堆内存中创建
#include "stdio.h" #include "string.h" #include "stdlib.h" typedef int ElemType; typedef struct node { struct node* next ; ElemType data; }Node; Node* Node_Init(void) { Node* head = (Node*)malloc(sizeof(Node)); head->next = NULL; head->data = 0; return head; }
创建一个节点
创建一个节点分两种方式头插法,尾插法
头插法:每次创建节点都在头节点的位置插入,头插法要先把头节点指向的下一个节点地址赋值给新创的节点next,再将头节点next指向新节点,如果先将头节点的next指向新节点,那后面节点的位置都找不着了
尾插法:在链表尾部插入节点,要想在尾部插入数据,要先找到尾节点,注:Node* M = L; 这里不能是 Node* M = L->next;,如果链表没有数据那M==NULL,下面的while循环执行不了,这里直接把头节点赋值给M ,这里返回尾节点,是为了下次插入更方便,让下次插入直接找到尾节点不用进入while循环,让代码运行更快
#include "stdio.h"
#include "string.h"
#include "stdlib.h"typedef int ElemType;
typedef struct node
{
struct node* next ;
ElemType data;
}Node;//初始化链表
Node* Node_Init(void)
{
Node* head = (Node*)malloc(sizeof(Node));
head->next = NULL;
head->data = 0;
return head;
}//创建一个节点(尾插法)
Node* Node_Tail_create(NodeL,ElemType e)
{
Node N = (Node*)malloc(sizeof(Node));
N->data = e;
//这里不能是M=L->next Node* M = L; while (M->next!= NULL) { M = M->next; } M->next = N; N->next = NULL; return N;}
//创建一个节点(头插法)
//每次插入数据都在头节点后面插入
void Node_head_create(Node* L,ElemType e)
{
Node* N = (Node*)malloc(sizeof(Node));
N->data = e;
//把头节点指向的节点地址赋值给新创的节点
N->next = L->next;
L->next = N;
}
遍历
void listNode(Node* L) { Node* M = L->next; while (M!= NULL) { printf("%d\n", M->data); M = M->next; } }
在指定位置插入
//在指定位置插入
void Inser_Node(Node* L, int pos,ElemType e)
{
Node* N = (Node*)malloc(sizeof(Node));
N->data = e;
//Node* M = L;
int i = 0;
while (i< pos-1)
{
L = L->next;
i++;
}
N->next = L->next;
L->next = N;
}
删除一个节点
删除节点一定要把该节点的空间释放掉
//删除节点(删除指定数字) void Delete_Node_1(Node* L, ElemType e) { while (L->next->data!= e&&L->data!=NULL) { L = L->next; if (L->next == NULL) { printf("该链表没有此数据"); } } Node*M; M = L->next->next; free(L->next); L->next = M; } //删除指定位置节点 void Delete_Node_2(Node* L, int pos) { for (int i=0;i < pos - 1;i++) { L = L->next; if (L == NULL) { printf("该链表没有这么长"); } } Node* M = L->next->next; free(L->next); L->next = M; }
获取链表长度
//获取链表长度
int ListLength(Node* L)
{
int i = 0;
for (i=0;L != NULL;i++)
{
L = L->next;
}
return i-1;
}
删除链表中重复出现的数据
链表的长度就是链表的最大值,如:链表长为6,链表最大数据为6
//链表最大值也是链表长度,删除链表中重复出现的数据 void removeNode(Node* L) { //计算出链表最大值 int M = 0; int MAX = 0; Node* L_1 = L->next; while (L_1 != NULL) { M = abs(L_1->data); if (M > MAX) { MAX = M; } L_1 = L_1->next; } printf("链表最大值为%d\n",MAX); //创建数值 int* arr = (int*)malloc(sizeof(int) * (MAX+1)); //给数值初始化 for (int i = 0;i <=MAX;i++) { arr[i] = 0; } int indet = 0; Node* prev=L; Node* curr = L->next; while(curr!=NULL) { indet = abs(curr->data); if (arr[indet] == 0) { arr[indet] = 1; prev = curr; curr = curr->next; } else if (arr[indet] == 1) { prev->next = curr->next; free(curr); curr = prev->next; } } free(arr); }
反转链表
//反转链表
Node* reverseList(Node* L)
{
Node* first = NULL;
Node* second = L->next;
Node* third = second->next;
while (second != NULL)
{
third = second->next;
second->next = first;
first = second;
second = third;
}
Node* head = (Node*)malloc(sizeof(Node));
head->next = first;
return head;
}
快慢指针
删除链表中间节点
//删除链表中间节点 Node* DeleMinddleNode(Node* L) { Node* S = L; Node* F = L->next; while (F != NULL) { F = F->next; if (F->next == NULL) { Node* M = S->next->next; free(S->next); S->next = M; return S; } S = S->next; F = F->next; if (F->next == NULL) { Node* M = S->next->next; free(S->next); S->next = M; return S; } }用快慢指针寻找倒数第K位置的数据
//寻找倒数第NUM个节点的数据 void findNode(Node* L,int NUM) { Node* K=L; Node* M=L; int a = 0; while (K ->next!= NULL) { K = K->next; a++; if (a >=NUM) { M = M->next; } } printf("%d\n", M->data); }
总代码
#include "stdio.h" #include "string.h" #include "stdlib.h" typedef int ElemType; typedef struct node { struct node* next ; ElemType data; }Node; //初始化链表 Node* Node_Init(void) { Node* head = (Node*)malloc(sizeof(Node)); head->next = NULL; head->data = 0; return head; } //创建一个节点(尾插法) Node* Node_Tail_create(Node*L,ElemType e) { Node* N = (Node*)malloc(sizeof(Node)); N->data = e; //这里不能是M=L->next Node* M = L; while (M->next!= NULL) { M = M->next; } M->next = N; N->next = NULL; return N; } //创建一个节点(头插法) //每次插入数据都在头节点后面插入 void Node_head_create(Node* L,ElemType e) { Node* N = (Node*)malloc(sizeof(Node)); N->data = e; //把头节点指向的节点地址赋值给新创的节点 N->next = L->next; L->next = N; } //遍历 void listNode(Node* L) { Node* M = L->next; while (M!= NULL) { printf("%d ", M->data); M = M->next; } printf("\n"); } //在指定位置插入 void Inser_Node(Node* L, int pos,ElemType e) { Node* N = (Node*)malloc(sizeof(Node)); N->data = e; //Node* M = L; int i = 0; while (i< pos-1) { L = L->next; i++; } N->next = L->next; L->next = N; } //删除节点(删除指定数字) void Delete_Node_1(Node* L, ElemType e) { while (L->next->data!= e&&L->next!=NULL) { L = L->next; if (L->next == NULL) { printf("该链表没有此数据"); } } Node*M; M = L->next->next; free(L->next); L->next = M; } //删除指定位置节点 void Delete_Node_2(Node* L, int pos) { for (int i=0;i < pos - 1;i++) { L = L->next; if (L == NULL) { printf("该链表没有这么长"); } } Node* M = L->next->next; free(L->next); L->next = M; } //获取链表长度 int ListLength(Node* L) { int i = 0; for (i=0;L != NULL;i++) { L = L->next; } return i-1; } void freeNode(Node* L) { while (L->next != NULL) { Delete_Node_2(L,1); } L->next = NULL; } //寻找倒数第NUM个节点的数据 void findNode(Node* L,int NUM) { Node* K=L; Node* M=L; int a = 0; while (K ->next!= NULL) { K = K->next; a++; if (a >=NUM) { M = M->next; } } printf("%d\n", M->data); } //链表最大值也是链表长度,删除链表中重复出现的数据 void removeNode(Node* L) { //计算出链表最大值 int M = 0; int MAX = 0; Node* L_1 = L->next; while (L_1 != NULL) { M = abs(L_1->data); if (M > MAX) { MAX = M; } L_1 = L_1->next; } printf("链表最大值为%d\n",MAX); //创建数值 int* arr = (int*)malloc(sizeof(int) * (MAX+1)); //给数值初始化 for (int i = 0;i <=MAX;i++) { arr[i] = 0; } int indet = 0; Node* prev=L; Node* curr = L->next; while(curr!=NULL) { indet = abs(curr->data); if (arr[indet] == 0) { arr[indet] = 1; prev = curr; curr = curr->next; } else if (arr[indet] == 1) { prev->next = curr->next; free(curr); curr = prev->next; } } free(arr); } //反转链表 Node* reverseList(Node* L) { Node* first = NULL; Node* second = L->next; Node* third; while (second != NULL) { third = second->next; second->next = first; first = second; second = third; } Node* head = (Node*)malloc(sizeof(Node)); head->next = first; free(L); return head; } //删除链表中间节点 Node* DeleMinddleNode(Node* L) { Node* S = L; Node* F = L->next; while (F != NULL) { F = F->next; if (F!=NULL&&F->next == NULL) { Node* M = S->next->next; free(S->next); S->next = M; return S; } S = S->next; F = F->next; if (F->next == NULL) { Node* M = S->next->next; free(S->next); S->next = M; return S; } } } void main(void) { //遍历尾插法 Node*list=Node_Init(); Node* tail=Node_Tail_create(list,1); tail = Node_Tail_create(tail, 2); tail = Node_Tail_create(tail, 1); tail = Node_Tail_create(tail, 4); tail = Node_Tail_create(tail, 2); tail = Node_Tail_create(tail, 4); tail = Node_Tail_create(tail, 7); tail = Node_Tail_create(tail, 8); listNode(list); removeNode(list); listNode(list); Node* list_1=reverseList(list); listNode(list_1); DeleMinddleNode(list_1); listNode(list_1); }
注:
在指定位置插入和尾插法,遍历都·可以把M换成L,因为在C语言中函数参数是值传递,并不能改变外面的list,在函数中改变L的地址和L的next都不会影响外面的list
循环链表
循环链表和单链表一样,只不过,循环链表的尾节点,指向的头节点,使整个链表形成一个环
当遍历循环链表时,判断遍历的条件是 L->next !=L,
当用尾插法添加数据时,新节点的next不是NULL了,是头节点
双向链表
单链表存储结构中有,数据和指向下一节点的指针,只能由前一个节点找后一个节点,而双链表的存储结构有,数据和指向下一节点的指针加指向上一节点的指针,这样就能实现从后一节点找前一节点了,