[关闭]
@yanglt7 2018-10-21T15:51:57.000000Z 字数 13098 阅读 742

03_线性表

数据结构和算法


3.1 定义

3.2 抽象数据类型

  1. ADT 抽象数据类型
  2. Data
  3. 数据元素之间逻辑关系的定义
  4. Operation
  5. 操作
  6. endADT

3.2.1 线性表的抽象数据类型

  1. ADT 线性表(List
  2. Data
  3. 线性表的数据对象集合为{a1,a2...,an},每个元素的类型均为DataType。其中,除第一个元素a1外,每一个元素有且仅有一个直接前驱元素,除了最后一个元素an外,每一个元素有且仅有一个直接后继元素。数据元素之间的关系是一对一的关系。
  4. Operation
  5. InitList(*L):初始化操作,建立一个空的线性表L
  6. ListEmpty(L):判断线性表是否为空表,若线性表为空,返回true,否则返回false
  7. ClearList(*L):将线性表清空。
  8. GetElem(L,i,*e):将线性表L中的第i个位置元素值返回给e
  9. Locate(L,e):在线性表L中查找与给定值e相等的元素,如果查找成功,返回该元素在表中序号表示成功;否则, 返回0表示失败。
  10. ListInsert(*L,i,e):在线性表L中第i个位置插入新元素e
  11. ListDelete(*L,i,*e):删除线性表L中第i个位置元素,并用e返回其值。
  12. ListLength(L):返回线性表L的元素个数。
  13. endADT

求两个集合的并集

  1. // La表示集合A,Lb表示集合B
  2. void unionL(List *La, List Lb)
  3. {
  4. int La_len,Lb_len,i;
  5. ElemType e;
  6. La_len = ListLength(*La);
  7. Lb_len = ListLength(Lb);
  8. for(i=1;i<=Lb_len;i++)
  9. {
  10. GetElem(Lb,i,&e);
  11. if (!LocateElem(*La,e))
  12. {
  13. ListInsert(La,++La_len,e);
  14. }
  15. }
  16. }

3.3 线性表的顺序存储结构

  1. #define MAXSIZE 20
  2. typedef int ElemType;
  3. typedef struct
  4. {
  5. ElemType data[MAXSIZE];
  6. int length; //线性表当前长度
  7. } SqList;

3.3.1 地址计算方法

3.3.2 获得元素操作

  1. #define OK 1
  2. #define ERROR 0
  3. #define TRUE 1
  4. #define FALSE 0
  5. typedef int Status;
  6. //Status 是函数的类型,其值是函数结果状态代码,如OK等
  7. //初始条件,顺序线性表L已存在,1<=i<=ListLength(L)
  8. //操作结果,用e返回L中第i个数据元素的值
  9. Status GetElem(SqList L, int i, ElemType *e)
  10. {
  11. if (L.length==0 || i<1 || i>L.length)
  12. {
  13. return ERROR;
  14. }
  15. *e = L.data(i-1);
  16. return OK;
  17. }

3.3.3 插入操作

  1. //初始条件,顺序线性表L已存在,1<=i<=ListLength(L).
  2. //操作结果:在L中第i个位置之前插入新的数据元素e,L长度+1.
  3. Status ListInsertSqList *L, int i, ElemType e)
  4. {
  5. int k;
  6. if (L->length == MAXSIZE)
  7. {
  8. return ERROR;
  9. }
  10. if (i<1 || i>L->length+1)
  11. {
  12. return ERROR;
  13. }
  14. if (i<=L->length)
  15. {
  16. for(k=L->length-1;k>=i-1;k--) {
  17. L->data[k+1] = L->data[k];
  18. }
  19. }
  20. L->data[i-1] = e;
  21. L->Length++;
  22. return OK;
  23. }

3.3.4 删除操作

  1. //初始条件,顺序线性表L已存在,1<=i<=ListLength(L).
  2. //操作结果:删除L的第i个数据元素,并用e返回其值,L长度-1.
  3. Status ListDelete(SqList *L, int i, ElemType *e)
  4. {
  5. int k;
  6. if (L->length == 0)
  7. {
  8. return ERROR;
  9. }
  10. if (i<1 || i>L->length)
  11. {
  12. return ERROR;
  13. }
  14. *e = L->data[i-1];
  15. if (i<L->length)
  16. {
  17. for(k=i;k<L->length;k++)
  18. {
  19. L->data[k-1] = L->data[k];
  20. }
  21. }
  22. L->length--;
  23. return OK;
  24. }

3.3.5 插入和删除操作的时间复杂度

3.3.6 线性表顺序存储结构的优缺点

3.4 线性表的链式存储结构

3.4.1 定义

3.4.2 单链表

3.4.2.1 头指针与头结点的异同

3.4.2.2 单链表的存储结构

  1. typedef struct Node
  2. {
  3. ElemType data;//数据域
  4. struct Node* Next;//指针域
  5. } Node;
  6. typedef struct Node* LinkList;

3.4.2.3 单链表的读取

  1. Status GetElem(LinkList L, int i, ELemType *e)
  2. {
  3. int j;
  4. LinkList p;
  5. P = L->next;
  6. j = 1;
  7. while(p && j<i)
  8. {
  9. p = p->next;
  10. ++j;
  11. }
  12. if (!p || j>i)
  13. {
  14. return ERROR;
  15. }
  16. *e = p->data;
  17. return OK;
  18. }

3.4.2.4 单链表的插入

  1. Status ListInsert(LinkList *L, int i, ELemType e)
  2. {
  3. int j;
  4. LinkList p;
  5. P = *L;
  6. j = 1;
  7. while(p && j<i)
  8. {
  9. p = p->next;
  10. ++j;
  11. }
  12. if (!p || j>i)
  13. {
  14. return ERROR;
  15. }
  16. s = (LinkList)malloc(sizeof(Node));
  17. s->data = e;
  18. s->next = p->next;
  19. p->next = s;
  20. return OK;
  21. }

3.4.2.5 单链表的删除

  1. Status ListDelete(LinkList *L, int i, ELemType *e)
  2. {
  3. int j;
  4. Linklist p,q;
  5. p = *L;
  6. j = 1;
  7. while(p->next && j<i)
  8. {
  9. p = p->next;
  10. ++j;
  11. }
  12. if (!(p->next) || j>i)
  13. {
  14. return ERROR;
  15. }
  16. q = p->next;
  17. p->next = q->next;
  18. *e = q->data;
  19. free(q);
  20. return OK;
  21. }

3.4.2.6 单链表的整表创建

3.4.2.7 头插法建立单链表

  1. void CreateListHead(LinkList *L, int n)
  2. {
  3. LinkList p;
  4. int i;
  5. srand(time(0));
  6. *L = (LinkList)malloc(sizeof(Node));
  7. (*L)->next = NULL;
  8. for(i=0; i<n; i++)
  9. {
  10. p = (LinkList)malloc(sizeof(Node));
  11. p->data = rand()%100+1;
  12. p->next = (*L)->next;
  13. (*L)->next = p;
  14. }
  15. }

3.4.2.8 尾插法建立单链表

  1. void CreateListTail(LinkList *L, int n)
  2. {
  3. LinkList p, r;
  4. int i;
  5. srand(time(0));
  6. *L = (LinkList)malloc(sizeof(Node));
  7. r = *L;
  8. for(i=0; i<n; i++)
  9. {
  10. p = (Node*)malloc(sizeof(Node));
  11. p->data = rand()%100+1;
  12. r->next = p;
  13. r = p;
  14. }
  15. r->next = NULL;
  16. }

3.4.2.9 单链表的整表删除

  1. Status ClearList(LinkList *L)
  2. {
  3. LinkList p, q;
  4. p = (*L)->next;
  5. while(p)
  6. {
  7. q = p->next;
  8. free(p);
  9. p = q;
  10. }
  11. (*L)->next = NULL;
  12. return OK;
  13. }

3.4.2.10 单链表结构与顺序存储结构优缺点

3.4.3 静态链表

  1. #define MAXSIZE 1000
  2. typedef struct
  3. {
  4. ElemType data; //数据
  5. int cur //游标(cursor)
  6. } Component, StaticLinkList [MAXSIZE];
游标 5 2 3 4 0 6 7 ... 1
数据 A C D E ...
下标 0 1 2 3 4 5 6 ... 999
  1. Status InitList(StaticLinkList space)
  2. {
  3. int i;
  4. for(i=0; i<MAXSIZE-1; i++)
  5. {
  6. space[i].cur = i+1;
  7. }
  8. space[MAXSIZE-1].cur = 0;
  9. return OK;
  10. }

3.4.3.1 静态链表的插入操作

游标 6 5 3 4 0 2 7 ... 1
数据 A C D E B ...
下标 0 1 2 3 4 5 6 ... 999
  1. int Malloc_SLL(StaticLinkList space)
  2. {
  3. int i = space[0].cur;
  4. if(space[0].cur)
  5. {
  6. space[0].cur = space[i].cur;//把它的下一个分量用来作为备用
  7. }
  8. return i;
  9. }
  1. //在静态链表L中第i=2个元素之前插入新的数据元素e
  2. Status ListInsert(StaticLinkList L, int i, ElemType e)
  3. {
  4. int j, k, l;
  5. k = MAXSIZE-1;
  6. if(i<1 || i>ListLength(L)+1)
  7. {
  8. return ERROR;
  9. }
  10. j = Malloc_SLL(L);
  11. if(j)
  12. {
  13. L[j].data = e;
  14. for(l=1; l<=i-1; l++)
  15. {
  16. k = L[k].cur;
  17. }
  18. L[j].cur = L[k].cur;
  19. L[k].cur = j;
  20. return OK;
  21. }
  22. return ERROR ;
  23. }

3.4.3.2 静态链表的删除操作

游标 2 5 6 4 0 3 7 ... 1
数据 A D E B ...
下标 0 1 2 3 4 5 6 ... 999
  1. //删除在L中的第i个数据元素
  2. Status ListDelete(StaticLinkList L, int i)
  3. {
  4. int j, k;
  5. k = MAXSIZE-1;
  6. if(i<1 || i>ListLength(L))
  7. {
  8. return ERROR;
  9. }
  10. for(j=1; j<=i-1; j++)
  11. {
  12. k = L[k].cur;
  13. }
  14. j = L[k].cur;
  15. L[k].cur = L[j].cur;
  16. Free_SLL(L,j);
  17. return OK;
  18. }
  19. //将下标为k的空闲结点回收到备用链表
  20. void Free_SLL(StaticLinkList space, int k)
  21. {
  22. space[k].cur = space[0].cur;
  23. space[0].cur = k;
  24. }
  25. //返回L中数据元素个数
  26. int ListLength(StaticLinkList L)
  27. {
  28. int j = 0;
  29. int i = L[MAXSIZE-1].cur;
  30. while(i)
  31. {
  32. i = L[i].cur;
  33. j++
  34. }
  35. return j;
  36. }

3.4.3.3 静态链表优缺点总结

3.4.4 单链表小结腾讯面试题

题目:快速找到未知长度单链表的中间结点并显示

  1. Status GetMidNode(StaticLinkList L, ElemType *e)
  2. {
  3. LinkList search, mid;
  4. mid = search = L;
  5. while(search->next != NULL)
  6. {
  7. //search移动的速度是mid的2倍
  8. if(search->next->next != NULL)
  9. {
  10. search = search->next->next;
  11. mid = mid->next;
  12. }
  13. else
  14. {
  15. search = search->next;
  16. }
  17. }
  18. *e = mid->data;
  19. return OK;
  20. }

3.4.5 循环链表

3.4.5.1 初始化循环链表

  1. //初始化循环链表
  2. void ds_init(node **pNode)
  3. {
  4. int item;
  5. node *temp;
  6. node *target;
  7. printf("输入结点的值,输入0完成初始化\n");
  8. while(1)
  9. {
  10. scanf("%d", &item);
  11. fflush(stdin);
  12. if(item==0)
  13. {
  14. return;
  15. }
  16. if((*pNode)==NULL)
  17. {
  18. //循环链表中只有一个结点
  19. *pNode = (node*)malloc(sizeof(struct CLinkList));
  20. if(!(*pNode))
  21. {
  22. exit(0);
  23. }
  24. (*pNode)->data = item;
  25. (*pNode)->next = *pNode;
  26. }
  27. else
  28. {
  29. //找到next指向第一个结点的结点
  30. for(target = (*pNode); target->next != (*pNode); target = target->next)
  31. ;
  32. //生成一个新的结点
  33. temp = (node*)malloc(sizeof(struct CLinkList));
  34. if(!temp)
  35. {
  36. exit(0);
  37. }
  38. temp->data = item;
  39. temp->next = *pNode;
  40. target->next = temp;
  41. }
  42. }
  43. }

3.4.5.2 插入结点

  1. //链表存储结构的定义
  2. typedef struct CLinkList
  3. {
  4. int data;
  5. struct CLinkList *next;
  6. }node;
  7. //插入结点
  8. //参数:链表的第一个结点,插入的位置
  9. void ds_insert(node **pNode, int i)
  10. {
  11. node *temp;
  12. node *target;
  13. node *p;
  14. int item;
  15. int j = 1;
  16. printf("输入要插入结点的值:");
  17. scanf("%d", &item);
  18. if(i==1)
  19. {
  20. //新插入的结点作为第一个结点
  21. temp = (node*)malloc(sizeof(struct CLinkList));
  22. if(!temp)
  23. {
  24. exit(0);
  25. }
  26. temp->data = item;
  27. //寻找到最后一个结点
  28. for(target = (*pNode); target->next != (*pNode); target = target->next)
  29. ;
  30. temp->next = (*pNode);
  31. target->next = temp;
  32. *pNode = temp;
  33. }
  34. else
  35. {
  36. target = *pNode;
  37. for(; j<(i-1); ++j)
  38. {
  39. target = target->next;
  40. }
  41. //target指向第三个元素的
  42. temp = (node*)malloc(sizeof(struct CLinkList));
  43. if(!temp)
  44. {
  45. exit(0);
  46. }
  47. temp->data = item;
  48. p = temp->next;
  49. target->next = temp;
  50. temp->next = p;
  51. }
  52. }

3.4.5.3 删除结点

  1. //删除结点
  2. void ds_delete(node **pNode, int i)
  3. {
  4. node *target;
  5. node *temp;
  6. int j = 1;
  7. if(i==1)
  8. {
  9. //删除的是第一个结点
  10. //找到的是最后一个结点
  11. for(target = *pNode; target->next != *pNode; target = target->next)
  12. ;
  13. temp = *pNode;
  14. *pNode = (*pNode)->next;
  15. target->next = *pNode;
  16. free(temp);
  17. }
  18. else
  19. {
  20. target = *pNode;
  21. for(; j < i-1; ++j)
  22. {
  23. target = target->next;
  24. target->next = temp->next;
  25. free(temp);
  26. }
  27. }
  28. }

3.4.5.4 返回结点所在位置

  1. //返回结点所在位置
  2. int ds_search(node *pNode, int elem)
  3. {
  4. node *target;
  5. int i = 1;
  6. for(target = pNode; target->data != elem && target->next != pNode; ++i)
  7. {
  8. target = target->next;
  9. }
  10. if(target->next == pNode)//表中不存在该元素
  11. return 0;
  12. else
  13. return i;
  14. }

3.4.6 约瑟夫环

  1. //n个人围圈报数,报m出列,最后剩下的是几号?
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. typedef struct node
  5. {
  6. int data;
  7. struct node *next;
  8. } node;
  9. node *create(int n)
  10. {
  11. node *p = NULL, *head;
  12. head = (node*)malloc(sizeof(node));
  13. p = head;
  14. node *s;
  15. int i = 1;
  16. if(0 != n)
  17. {
  18. while (i<=n)
  19. {
  20. s = (node *)malloc(sizeof(node));
  21. s->data = i++;
  22. p->next = s;
  23. p = s;
  24. }
  25. s->next = head->next;
  26. }
  27. free(head);
  28. return s->next;
  29. }
  30. int main()
  31. {
  32. int n = 41;
  33. int m = 3;
  34. int i;
  35. node *p = create(n);
  36. node *temp;
  37. m %= n;
  38. while(p!=p->next)
  39. {
  40. for(i=1; i<m-1; i++)
  41. {
  42. p = p->next;
  43. }
  44. printf("%d->", p->next->data);
  45. temp = p->next;
  46. p->next = temp->next;
  47. free(temp);
  48. p = p->next;
  49. }
  50. printf("%d\n", p->data);
  51. return 0;
  52. }

3.4.7 连接A、B两个循环链表为一个循环链表

  1. // 假设A,B为非空循环链表的尾指针
  2. LinkList Connect(LinkList A, LinkList B)
  3. {
  4. LinkList p = A->next; //保存A表的头结点位置
  5. A->next = B->next->next; //B表的开始结点链接到A表尾
  6. free(B->next); //释放B表的头结点
  7. B->next = p;
  8. return B; //返回新循环链表的尾指针
  9. }

3.4.8 判断单链表是否有环

  1. //比较步数的方法
  2. int HasLoop1(LinkList L)
  3. {
  4. LinkList cur1 = L; //定义结点 cur1
  5. int pos1 = 0; // cur2 的步数
  6. while(cur1)
  7. { //cur1 结点存在
  8. LinkList cur2 = L; //定义结点 cur2
  9. int pos2 = 0; // cur2 的步数
  10. while(cur2)
  11. { //cur2 结点不为空
  12. if(cur2 == cur1)
  13. { //当cur1和cur2到达相同结点时,走过的步数一样,说明没有环
  14. if(pos1 == pos2)
  15. break;
  16. else
  17. {
  18. printf("环的位置在第%d个结点处\n", pos2);
  19. return 1; //有环并返回1
  20. }
  21. }
  22. cur2 = cur2->next; //如果发现没有环,继续下一个结点
  23. pos2++; //cur2步数自增
  24. }
  25. cur1 = cur1->next; //cur1继续向后一个结点
  26. pos1++; //cur1步数自增
  27. }
  28. return 0;
  29. }
  1. //利用快慢指针的方法
  2. int HasLoop2(LinkList L)
  3. {
  4. int step1 = 1;
  5. int step2 = 2
  6. LinkList p = L;
  7. LinkList q = L;
  8. while(p != NULL && q != NULL && q->next != NULL)
  9. {
  10. p = p->next;
  11. if(q->next != NULL)
  12. q = q->next->next;
  13. printf("p:%d, q:%d \n", p->data, q->data);
  14. if(p==q)
  15. return 1;
  16. }
  17. return 0;
  18. }

3.4.9 魔术师发牌问题

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #define CardNumber 13
  4. typedef struct node
  5. {
  6. int data;
  7. struct node *next;
  8. } sqlist, *linklist;
  9. linklist CreateLinkList()
  10. {
  11. linklist head = NULL;
  12. linklist s, r;
  13. int i;
  14. r = head;
  15. for(i=1; i<=CardNumber; i++)
  16. {
  17. s = (linklist)malloc(sizeof(sqlist));
  18. s->data = 0;
  19. if(head == NULL)
  20. head = s;
  21. else
  22. r->next = s;
  23. r = s;
  24. }
  25. r->next = head;
  26. return head;
  27. }
  28. //发牌顺序计算
  29. void Magician(linklist head)
  30. {
  31. linklist p;
  32. int j;
  33. int countnumber = 2;
  34. p = head;
  35. p->data = 1; //第一张牌放1
  36. while(1)
  37. {
  38. for(j=0; j<countnumber; j++)
  39. {
  40. p = p->next;
  41. if(p->data != 0) //该位置有牌的话,则下一个位置
  42. {
  43. p->next;
  44. j--;
  45. }
  46. }
  47. if(p->data == 0)
  48. {
  49. p->data = countnumber;
  50. countnumber++;
  51. if(countnumber == 14)
  52. break;
  53. }
  54. }
  55. }
  56. int main()
  57. {
  58. linklist p;
  59. int i;
  60. p = CreateLinkList();
  61. Magician(p);
  62. printf("按如下顺序排列: \n");
  63. for(i=0; i<CardNumber; i++)
  64. {
  65. printf("黑桃%d ", p->data);
  66. p = p->next;
  67. }
  68. return 0;
  69. }

3.4.10 双向链表

3.4.10.1 双向链表结点结构

  1. typedef struct DualNode
  2. {
  3. ElemType data;
  4. struct DualNode *prior;
  5. struct DualNode *next;
  6. }DualNode, *DuLinkList;

3.4.10.2 双向链表的插入操作

  1. s->next = p;
  2. s->prior = p->prior;
  3. p->prior->next = s;
  4. p->prior = s;

3.4.10.3 双向链表的删除操作

  1. p->prior->next = p->next;
  2. p->next->prior = p->prior;
  3. free(p);

3.4.11 Caesar

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #define OK 1
  4. #define ERROR 0
  5. typedef char ElemType;
  6. typedef int Status;
  7. typedef struct DualNode
  8. {
  9. ElemType data;
  10. struct DualNode *prior;
  11. struct DualNode *next;
  12. }DualNode, *DuLinkList;
  13. Status InitList(DuLinkList *L)
  14. {
  15. DualNode *p, *q;
  16. int i;
  17. *L = (DuLinkList)malloc(sizeof(DualNode));
  18. if (!(*L))
  19. return ERROR;
  20. (*L)->prior = (*L)->next = NULL;
  21. p = (*L);
  22. for(i=0; i<26; i++)
  23. {
  24. q = (DualNode *)malloc(sizeof(DualNode));
  25. if (!q)
  26. return ERROR;
  27. q->data = 'A'+i;
  28. q->prior = p;
  29. q->next = p->next;
  30. p->next = q;
  31. p = q;
  32. }
  33. p->next = (*L)->next;
  34. (*L)->next->prior = p;
  35. return OK;
  36. }
  37. void Caesar(DuLinkList *L, int i)
  38. {
  39. if (i>0)
  40. {
  41. do
  42. {
  43. (*L) = (*L)->next;
  44. } while(--i);
  45. }
  46. if(i<0)
  47. {
  48. do
  49. {
  50. (*L) = (*L)->next;
  51. } while(++i);
  52. }
  53. }
  54. int main()
  55. {
  56. DuLinkList L;
  57. int i, n;
  58. InitList(&L);
  59. printf("请输入一个整数:");
  60. scanf("%d", &n);
  61. printf("\n");
  62. Caesar(&L, n);
  63. for(i=0; i<26; i++)
  64. {
  65. L = L->next;
  66. printf("%c", L->data);
  67. }
  68. printf("\n");
  69. return 0;
  70. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注