一、线性表

线性表是最基本、最简单,也是最常用的一种数据结构。 一个线性表(linear list)是n个具有相同特性的数据元素的有限序列。 数据元素之间的关系是一对一

线性、非线性是在逻辑层次上讨论,不考虑存储层次

1.1 顺序表

顺序存储,逻辑相邻,物理存储地址也相邻

1.1.1 数据结构声明

  1. #define MAXSIZE 100
  2. #define OK 1
  3. #define ERROR 0
  4. #define TRUE 1
  5. #define FALSE 0
  6. /* ElementType类型根据实际情况而定,这里假设为int */
  7. typedef int ElementType;
  8. /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
  9. typedef int Status;
  10. //顺序表结构设计
  11. typedef struct {
  12. ElementType *data;
  13. int length;
  14. }Sequencelist;

1.1.2.顺序表初始化

  1. Status InitList(Sequencelist *list){
  2. //为顺序表分配一个大小为MAXSIZE 的数组空间
  3. list->data = malloc(sizeof(ElementType) * MAXSIZE);
  4. //存储分配失败退出
  5. if(!list->data) exit(ERROR);
  6. //空表长度为0
  7. list->length = 0;
  8. return OK;
  9. }

1.1.3.顺序表的插入

  1. Status ListInsert(Sequencelist *list,int i,ElementType e){
  2. //i值不合法判断
  3. if((i<1) || (i>list->length+1)) return ERROR;
  4. //存储空间已满
  5. if(list->length == MAXSIZE) return ERROR;
  6. //插入数据不在表尾,则先移动出空余位置
  7. if(i <= list->length){
  8. for(int j = list->length-1; j>=i-1;j--){
  9. //插入位置以及之后的位置后移动1位
  10. list->data[j+1] = list->data[j];
  11. }
  12. }
  13. //将新元素e 放入第i个位置上
  14. list->data[i-1] = e;
  15. //长度+1;
  16. ++list->length;
  17. return OK;
  18. }

1.1.4.顺序标的取值

  1. Status GetElem(Sqlist L,int i, ElemType *e){
  2. //判断i值是否合理, 若不合理,返回ERROR
  3. if(i<1 || i > L.length) return ERROR;
  4. //data[i-1]单元存储第i个数据元素.
  5. *e = L.data[i-1];
  6. return OK;
  7. }

1.1.5顺序表的删除

  1. /*
  2. 初始条件:顺序线性表L已存在,1≤i≤ListLength(L)
  3. 操作结果: 删除L的第i个数据元素,L的长度减1
  4. */
  5. Status ListDelete(Sqlist *L,int i){
  6. //线性表为空
  7. if(L->length == 0) return ERROR;
  8. //i值不合法判断
  9. if((i<1) || (i>L->length)) return ERROR;
  10. for(int j = i; j < L->length;j++){
  11. //被删除元素之后的元素向前移动
  12. L->data[j-1] = L->data[j];
  13. }
  14. //表长度-1;
  15. L->length --;
  16. return OK;
  17. }

1.1.6 清空顺序表

  1. /* 初始条件:顺序线性表L已存在。操作结果:将L重置为空表 */
  2. Status ClearList(Sqlist *L)
  3. {
  4. L->length=0;
  5. return OK;
  6. }

1.1.7.判断顺序表是否为空

  1. /* 初始条件:顺序线性表L已存在。操作结果:若L为空表,则返回TRUE,否则返回FALSE */
  2. Status ListEmpty(Sqlist L)
  3. {
  4. if(L.length==0)
  5. return TRUE;
  6. else
  7. return FALSE;
  8. }

1.1.8 获取顺序表的长度

  1. //1.7 获取顺序表长度ListEmpty元素个数 */
  2. int ListLength(Sqlist L)
  3. {
  4. return L.length;
  5. }

1.1.9 顺序表的查找

  1. /* 初始条件:顺序线性表L已存在 */
  2. /* 操作结果:返回L中第1个与e满足关系的数据元素的位序。 */
  3. /* 若这样的数据元素不存在,则返回值为0 */
  4. int LocateElem(Sqlist L,ElemType e)
  5. {
  6. int i;
  7. if (L.length==0) return 0;
  8. for(i=0;i<L.length;i++)
  9. {
  10. if (L.data[i]==e)
  11. break;
  12. }
  13. if(i>=L.length) return 0;
  14. return i+1;
  15. }

1.2 单链表

链式存取,用一组地址任意存储单元存放线性表中的数据元素 此处我们引入了头结点,哨兵

数据结构声明
001.png

结点

  1. #define MAXSIZE 100
  2. #define OK 1
  3. #define ERROR 0
  4. #define TRUE 1
  5. #define FALSE 0
  6. /* ElementType类型根据实际情况而定,这里假设为int */
  7. typedef int ElementType;
  8. /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
  9. typedef int Status;
  10. //单链表结构设计
  11. typedef struct {
  12. ElementType data;//数据
  13. struct Node *next;//指针域
  14. }Node;
  15. typedef struct Node * LinkList;

1.2.1.初始化

002.png

  1. Status InitList(LinkList *list){
  2. //初始化哨兵,听起来高大上
  3. *list = (LinkList)malloc(sizeof(Node));
  4. //存储空间分配失败
  5. if(*list == NULL) return ERROR;
  6. //将头结点的指针域置NULL
  7. (*list)->next = NULL;
  8. return OK;
  9. }

1.2.2 遍历Traverse

  1. Status ListTraverse(LinkList list)
  2. {
  3. LinkList p = list->next;
  4. while(p)
  5. {
  6. printf("%d\n",p->data);
  7. p = p->next;
  8. }
  9. return OK;
  10. }

1.2.3 单链表插入

截屏2020-07-17 下午4.48.51.png

  1. /*
  2. 初始条件:顺序线性表L已存在,1≤i≤ListLength(L);
  3. 操作结果:在L中第i个位置之后插入新的数据元素e,L的长度加1;
  4. */
  5. Status ListInsert(LinkList *L,int i,ElemType e){
  6. int j;
  7. LinkList p,s;
  8. p = *L;
  9. j = 1;
  10. //寻找第i-1个结点
  11. while (p && j<i) {
  12. p = p->next;
  13. ++j;
  14. }
  15. //第i个元素不存在
  16. if(!p || j>i) return ERROR;
  17. //生成新结点s
  18. s = (LinkList)malloc(sizeof(Node));
  19. //将e赋值给s的数值域
  20. s->data = e;
  21. //将p的后继结点赋值给s的后继
  22. s->next = p->next;
  23. //将s赋值给p的后继
  24. p->next = s;
  25. return OK;
  26. }

1.2.4 单链表读取值

  1. /*
  2. 初始条件: 顺序线性表L已存在,1≤i≤ListLength(L);
  3. 操作结果:用e返回L中第i个数据元素的值
  4. */
  5. Status GetElem(LinkList L,int i,ElemType *e){
  6. //j: 计数.
  7. int j;
  8. //声明结点p;
  9. LinkList p;
  10. //将结点p 指向链表L的第一个结点;
  11. p = L->next;
  12. //j计算=1;
  13. j = 1;
  14. //p不为空,且计算j不等于i,则循环继续
  15. while (p && j<i) {
  16. //p指向下一个结点
  17. p = p->next;
  18. ++j;
  19. }
  20. //如果p为空或者j>i,则返回error
  21. if(!p || j > i) return ERROR;
  22. //e = p所指的结点的data
  23. *e = p->data;
  24. return OK;
  25. }

1.2.5 单链表删除元素

  1. /*
  2. 初始条件:顺序线性表L已存在,1≤i≤ListLength(L)
  3. 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1
  4. */
  5. Status ListDelete(LinkList *L,int i,ElemType *e){
  6. int j;
  7. LinkList p,q;
  8. p = (*L)->next;
  9. j = 1;
  10. //查找第i-1个结点,p指向该结点
  11. while (p->next && j<(i-1)) {
  12. p = p->next;
  13. ++j;
  14. }
  15. //当i>n 或者 i<1 时,删除位置不合理
  16. if (!(p->next) || (j>i-1)) return ERROR;
  17. //q指向要删除的结点
  18. q = p->next;
  19. //将q的后继赋值给p的后继
  20. p->next = q->next;
  21. //将q结点中的数据给e
  22. *e = q->data;
  23. //让系统回收此结点,释放内存;
  24. free(q);
  25. return OK;
  26. }

1.2.6 清空链表

  1. /* 初始条件:顺序线性表L已存在。操作结果:将L重置为空表 */
  2. Status ClearList(LinkList *L)
  3. {
  4. LinkList p,q;
  5. p=(*L)->next; /* p指向第一个结点 */
  6. while(p) /* 没到表尾 */
  7. {
  8. q=p->next;
  9. free(p);
  10. p=q;
  11. }
  12. (*L)->next=NULL; /* 头结点指针域为空 */
  13. return OK;
  14. }

1.2.7 单链表前插入法

003.png

  1. /* 随机产生n个元素值,建立带表头结点的单链线性表L(前插法)*/
  2. void CreateListHead(LinkList *L, int n){
  3. LinkList p;
  4. //建立1个带头结点的单链表
  5. *L = (LinkList)malloc(sizeof(Node));
  6. (*L)->next = NULL;
  7. //循环前插入随机数据
  8. for(int i = 0; i < n;i++)
  9. {
  10. //生成新结点
  11. p = (LinkList)malloc(sizeof(Node));
  12. //i赋值给新结点的data
  13. p->data = i;
  14. //p->next = 头结点的L->next
  15. p->next = (*L)->next;
  16. //将结点P插入到头结点之后;
  17. (*L)->next = p;
  18. }
  19. }

1.2.8 单链表后插入法

004.png

  1. /* 随机产生n个元素值,建立带表头结点的单链线性表L(后插法)*/
  2. void CreateListTail(LinkList *L, int n){
  3. LinkList p,r;
  4. //建立1个带头结点的单链表
  5. *L = (LinkList)malloc(sizeof(Node));
  6. //r指向尾部的结点
  7. r = *L;
  8. for (int i=0; i<n; i++) {
  9. //生成新结点
  10. p = (Node *)malloc(sizeof(Node));
  11. p->data = i;
  12. //将表尾终端结点的指针指向新结点
  13. r->next = p;
  14. //将当前的新结点定义为表尾终端结点
  15. r = p;
  16. }
  17. //将尾指针的next = null
  18. r->next = NULL;
  19. }