目录
一、线性表
1.1、顺序表
1.1.1、定义顺序表(静态分配)
1.1.2、初始化InitList(&L)(静态分配)
1.1.3、定义顺序表(动态分配)
1.1.4、初始化InitList(&L)(动态分配)
1.1.5、插入元素ListInsert(&L, i, e)
1.1.6、删除元素ListDelete(&L, i, &e)
1.1.7、按值查找 LocateElem(&L, i, e)
1.1.8、测试
1.2、单链表
1.2.1、定义链表
1.2.2、初始化链表
1.2.3、头插法
1.2.4、尾插法
1.2.5、按序号查找节点
1.2.6、按值查找节点
1.2.7、插入元素
1.2.8、删除元素
1.3、双链表
1.3.1、双链表的类型定义
1.3.2、双链表的插入操作
1.3.3、双链表的删除操作
一、线性表
线性表一般包含以下功能:
初始化线性表:将一个线性表进行初始化,得到一个全新的线性表。
获取指定位置上的元素:直接获取线性表指定位置i上的元素。
获取元素的位置:获取某个元素在线性表上的位置i。
插入元素:在指定位置i上插入一个元素。
删除元素:删除指定位置i上的一个元素。
获取长度:返回线性表的长度。
线性表的结构一般有两种,一种是顺序存储实现,还有一种是链式存储实现。
1.1、顺序表
1.1.1、定义顺序表(静态分配)
#define Maxsize 50 //定义线性表最大长度
typedef int ElemType; //定义元素类型
typedef struct { //定义结构体ElemType data[Maxsize]; //定义顺序表的元素int length; //定义线性表的长度
}SqList;
1.1.2、初始化InitList(&L)(静态分配)
void InitList(SqList *L){L -> length = 10;
}
1.1.3、定义顺序表(动态分配)
typedef int ElemType; //定义元素类型
typedef struct { //定义结构体ElemType *data; //定义顺序表的元素int length; //定义线性表的长度int Maxsize; //定义最大长度
}SqList;
1.1.4、初始化InitList(&L)(动态分配)
_Bool InitList(SqList *L){L->length = 10;L->data = malloc(sizeof (ElemType) * L->length); //malloc函数手动申请一片空间if(L->data == NULL) return false; // 如果申请的结果为NULL表示内存空间分配失败L->Maxsize = 0; //默认长度0return true;
}
1.1.5、插入元素ListInsert(&L, i, e)
//在位置i插入元素e
_Bool ListInsert(SqList *L, int i, ElemType e){if(i < 1 || i > L->length + 1) return false; //判断i是否合法,小于1或者大于最大长度返回falseif(L->length > L->Maxsize) return false; //存储空间已满,不可插入
// j为顺序表的长度,将j向i靠近(j--)到达i的位置for (int j = L->length; j >= i; j--) {L->data[j] = L->data[j - 1]; //将j位置的元素后移一位,通过for不断循环直到到达i位置,此时候原数组中i位置空缺
}L->data[i - 1] = e; //此时j在i的位置,由于顺序表从0开始,在i位置就是在L.data[j-1]插入L->length++; //顺序表长度+1return true;
}
1.1.6、删除元素ListDelete(&L, i, &e)
//在第i个位置删除元素e
_Bool ListDelete(SqList *L, int i, ElemType *e){if(i < 1 || i > L->length + 1) return false; //判断i是否合法,小于1或者大于最大长度返回falsee = L->data[i - 1]; //将第i个位置的元素赋给e,此时顺序表中第i个位置空for (int j = i; j < L->length; j++) {L->data[j - 1] = L->data[j]; //循环,将第j个赋给第j-1个,也就是向前放}L->length--; //长度减1return true;
}
1.1.7、按值查找 LocateElem(&L, i, e)
//按值查找
int LocateElem(SqList *L, ElemType e) {int i;for (i = 0; i < L->length; i++) { //遍历顺序表if (L->data[i] == e) return i + 1; //当L.data[i] == e时,返回该元素的位序,i是该元素的下标}return 0;
}
1.1.8、测试
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
typedef int ElemType;
//定义一个顺序表,动态存储
typedef struct {ElemType *data;int length,Maxsize;
}SqList;//初始化一个顺序表
_Bool InitList(SqList *L){L->data = malloc(sizeof (ElemType) * L->length);if(L->data == NULL) return false;L->length = 0; //初始化为0L->Maxsize = 50; // 定义最大长度return true;
}//插入元素
//在i位置插入元素e
_Bool ListInsert (SqList *L, int i, ElemType e){if(i < 1 || i > L->length + 1) return false;if(i > L->Maxsize) return false;for (int j = L->length; j >= i; j--) {L->data[j] = L->data[j-1];}L->data[i-1] = e;L->length ++;return true;
}//删除元素
_Bool ListDelete(SqList *L, int i, ElemType *e){if(i < 1 || i > L->length + 1) return false;if(i > L->Maxsize) return false;e = L->data[i-1];for (int j = i; j < L->length; j++) {L->data[j-1] = L->data[j];}L->length --;return true;
}int ListSize(SqList *L){return L->length;
}//按值查找
int LocateElem(SqList *L, ElemType e) {int i;for (i = 0; i < L->length; i++) { //遍历顺序表if (L->data[i] == e) return i + 1; //当L.data[i] == e时,返回该元素的位序,i是该元素的下标}return 0;
}void printList(SqList *L){for (int i = 0; i < L->length; ++i) {printf("%d", L->data[i]);}printf("\n");
}int main() {SqList L;InitList(&L);ListInsert(&L, 1, 6);printList(&L);ListInsert(&L, 2, 44);printList(&L);ListInsert(&L, 3, 444);printList(&L);
}
1.2、单链表
链表不同于顺序表,顺序表采用数组作为存储容器,需要分配一块连续且完整的内存空间进行使用,而链表则不需要,它通过一个指针来连接各个分散的节点,形成一个链状的结构。它不需要申请连续的空间,只需要按照顺序连接即可,逻辑上依然相邻。
1.2.1、定义链表
typedef int ElemType;
typedef struct LNode{ElemType data; //数据域struct LNode * next; //指向下一节点的指针
}LNode, *LinkList;
1.2.2、初始化链表
void InitList(LNode *L){ // 将定义的结构体命名为LL->next = NULL; // 链表L中的next指针指向NULL
}
1.2.3、头插法
//头插法
LinkList List_HeadInsert(LinkList &L){LNode *s; int x; //定义结点指针s,插入数据xL = (LinkList)malloc(sizeof (LNode)); //创建头结点,前面表示LinkList型的L->next = NULL; //初始化链表,指针指向NULLscanf("%d", &x); //输入结点的值,也就是数据域while (x!=9999) { //输入9999时表示结束链表创建s = (LNode *) malloc(sizeof(LNode)); //创建一个新的,待插入的结点s->data = x;s->next = L->next;L->next = s;scanf("%d", &x); //继续读取数据,读一次插一次}return L; }
1.2.4、尾插法
//尾插法
LinkList List_TailInsert(LinkList L){int x; //数据域L = (LinkList) malloc(sizeof (LNode)); //为链表开创一段内存空间LNode *s, *r=L; //定义两个指针,其中r是表尾指针,s是指向新结点的指针scanf("%d", &x); //通过输入接受到数据xwhile (x!=9999) {s = (LNode *) malloc(sizeof(LNode)); //为待插入的结点赋予一段内存空间s->data = x;r->next = s;r = s;scanf("%d", &x);}r->next = NULL; //表尾指针置空return L;}
1.2.5、按序号查找节点
//按序号查找节点,序号为i
_Bool GetElem(LinkList L, int i) {if (i < 1) return 0; //当序号小于1时,此时不存在,返回0int j = 1; //计数LNode *p = L->next; //第一个位置赋值给pwhile (p != NULL && j < i) { //当j<i时继续遍历,当j=i时跳出遍历,当p不断后移后直到NULL,跳出循环p = p->next; //当j<i时候p指向它的下一个节点j++; // 遍历一次j就+1}return p;
}
1.2.6、按值查找节点
LNode *LocateElem(LinkList L, ElemType e){ //待查找的链表L 数据元素为eLNode *p = L->next; // p指向头结点while (p!=NULL && p->data != e) // 当p为空或查找到p的数据域为e时跳出循环p = p->next; // 没找到,向后指,p指向下一节点return p;
}
1.2.7、插入元素
P = GetElem(L, i-1); //调用GetElem函数找到前驱节点
s -> next = p -> next; // 结构同前面头插法
p -> next = s;
1.2.8、删除元素
p = GetElem(L, i-1); //调用GetElem函数获取待删除元素前一个位置
q = p -> next; // q指针指向待删除结点
p -> next = q -> next; // p指向q的后一个结点
free(q); // 释放q结点
1.3、双链表
1.3.1、双链表的类型定义
typedef int ElemType;
//定义双链表的结点类型
typedef struct DNode{ElemType data; //数据域struct DNode *prior, *next; // 前驱结点的指针;后继结点的指针
}DNode, *DLinklist;
1.3.2、双链表的插入操作
一图胜千言
s -> next = p -> next;
p -> next -> prior = s;
s -> prior = p;
p -> next = s;
1.3.3、双链表的删除操作
p->next = q->next;
q->next->prior=p;
free(q);