当前位置:   article > 正文

数据结构---线性表

数据结构---线性表

1,顺序表实现---动态分配

  1. #include<stdlib.h>
  2. #define InitSize 10
  3. typedef struct {
  4. int *data;//静态分配
  5. int length;
  6. int MaxSize;
  7. }SqList;
  8. void InitList(SqList& L)
  9. {
  10. L.data = (int*)malloc(InitSize * sizeof(int));//分配空间
  11. L.length = 0;
  12. L.MaxSize = InitSize;//初始空间为10
  13. }
  14. void ListInsert(SqList& L, int x, int a)
  15. {
  16. L.data[x] = a;
  17. }
  18. void Increaselength(SqList& L, int len)
  19. {
  20. int *p = L.data;
  21. L.data = (int*)malloc((InitSize + len) * sizeof(int));//重新开辟空间
  22. for (int i = 0; i < L.MaxSize;i++)
  23. {
  24. L.data[i] = p[i];
  25. }
  26. L.MaxSize = InitSize + len;
  27. free(p);
  28. }
  29. int main()
  30. {
  31. SqList q;
  32. InitList(q);
  33. ListInsert(q, 2, 4);
  34. Increaselength(q, 5);
  35. ListInsert(q, 12, 2);
  36. printf("data[2]=%d,data[12]=%d", q.data[2], q.data[12]);
  37. system("pause");
  38. return 0;
  39. }

 第i个元素中的i表示的是位序

2, 静态分配的插入与删除操作:

2.1插入操作:

  1. typedef struct {
  2. int data[MaxSize];
  3. int length;
  4. }SqList;
  5. void InitList(SqList& L)
  6. {
  7. L.length = 0;
  8. for (int i = 0; i <MaxSize-1; i++)
  9. {
  10. L.data[i] = i;//赋予原始数据,注意不要插满
  11. L.length++;
  12. }
  13. }
  14. bool ListInsert(SqList &L,int i,int e)//在第i个位置插入e
  15. {
  16. if (i<1 || i>L.length + 1)
  17. return false;
  18. if (L.length >= MaxSize)//存储空间已满
  19. {
  20. return false;
  21. }
  22. for(int j=L.length;j>=i;j--)
  23. {
  24. L.data[j] = L.data[j - 1];
  25. }
  26. L.data[i - 1] = e;
  27. L.length++;
  28. return true;
  29. }
  30. int main()
  31. {
  32. SqList L;
  33. InitList(L);
  34. if (ListInsert(L, 8, 1))
  35. {
  36. printf("data[7]=%d ", L.data[7]);//验证插入
  37. }
  38. system("pause");
  39. return 0;
  40. }

2.2,删除操作:

  1. typedef struct {
  2. int data[MaxSize];
  3. int length;
  4. }SqList;
  5. void InitList(SqList& L)
  6. {
  7. L.length = 0;
  8. for (int i = 0; i < MaxSize - 1; i++)
  9. {
  10. L.data[i] = i;//赋予原始数据,注意不要插满
  11. L.length++;
  12. }
  13. }
  14. bool ListDelete(SqList &L,int i,int &e)//在第i个位置插入e
  15. {
  16. if (i<1 || i>L.length)
  17. return false;
  18. e=L.data[i - 1];//赋值
  19. for(int j=i;j<L.length;j++)
  20. {
  21. L.data[j-1] = L.data[j];
  22. }
  23. L.length--;
  24. return true;
  25. }
  26. int main()
  27. {
  28. SqList L;
  29. InitList(L);
  30. int e = -1;
  31. if (ListDelete(L, 8, e))//位置8的元素是7
  32. {
  33. printf("删除的元素是%d data[7]=%d", e,L.data[7]);//验证删除,删除后data[7]=8
  34. }
  35. system("pause");
  36. return 0;
  37. }

3,顺序表的查找:

3.1按位查找

动态分配和普通数组访问方式相同,时间复杂度为O(1)

  1. GetElem(SqList L,int i)
  2. {
  3. return L.data[i-1];
  4. }

3.2按值查找

动态分配方式:

  1. int LocatElem(SqList L, int e)
  2. {
  3. for(int i=0;i<L.length;i++)
  4. {
  5. if(L.data[i]==e)
  6. return i+1;
  7. }
  8. return 0;}

4,链表初始化

4.1不带头结点的单链表的初始化:

与顺序表不同,单链表是用指针来定义

  1. typedef struct LNode {
  2. int data;
  3. struct LNode* next;//每个元素包括数据和指向下一个节点的指针
  4. }LNode,*LinkList;//LNode*等价于LinkList
  5. bool InitList(LinkList &L)//声明是一个单链表
  6. {
  7. L = NULL;
  8. return true;
  9. }
  10. bool IsEmpty(LinkList &L)//声明是一个单链表
  11. {
  12. return (L == NULL);
  13. }
  14. int main()
  15. {
  16. LinkList L;//声明一个指向单链表的指针
  17. InitList(L);
  18. if(IsEmpty(L))
  19. printf("初始化成功");
  20. system("pause");
  21. return 0;
  22. }

4.2,带头结点的单链表的初始化: 

  1. typedef struct LNode {
  2. int data;
  3. struct LNode* next;//每个元素包括数据和指向下一个节点的指针
  4. }LNode,*LinkList;//LNode*等价于LinkList
  5. bool InitList(LinkList &L)//声明是一个单链表
  6. {
  7. L = (LNode*)malloc(sizeof(LNode));//头指针指向下一个节点:即为头节点
  8. if (L == NULL)
  9. return false;//没有内存,分配失败
  10. L->next = NULL;//头节点暂时没有节点
  11. return true;
  12. }
  13. bool IsEmpty(LinkList &L)//声明是一个单链表
  14. {
  15. return (L == NULL);
  16. }
  17. int main()
  18. {
  19. LinkList L;
  20. InitList(L);
  21. if(IsEmpty(L)==false)
  22. printf("初始化成功");
  23. system("pause");
  24. return 0;
  25. }

5,链表插入操作:

5.1,带头结点,按位序插入:

  1. typedef struct LNode {
  2. int data;
  3. struct LNode* next;//每个元素包括数据和指向下一个节点的指针
  4. }LNode,*LinkList;//LNode*等价于LinkList
  5. //带头结点按位序插入
  6. bool ListInsert(LinkList& L,int i,int e)//在第i个位置插入e
  7. {
  8. if (i < 1)
  9. return false;
  10. int j = 0;
  11. LNode *p;
  12. p= L;//是从第0个节点开始遍历,所以p应该与头节点相同
  13. while (p != NULL && j < i - 1)//找到第i-1的节点
  14. {
  15. p = p->next;
  16. j++;
  17. }
  18. if (p == NULL)//超出链表长度
  19. {
  20. return false;
  21. }
  22. LNode *s = (LNode*)malloc(sizeof(LNode));
  23. s->data = e;
  24. s->next = p->next;
  25. p->next = s;
  26. return true;
  27. }
  28. bool InitList(LinkList &L)//声明是一个单链表
  29. {
  30. L = (LNode*)malloc(sizeof(LNode));//头指针指向下一个节点:即为头节点
  31. if (L == NULL)
  32. return false;//没有内存,分配失败
  33. L->next = NULL;//头节点暂时没有节点
  34. return true;
  35. }
  36. bool IsEmpty(LinkList &L)//声明是一个单链表
  37. {
  38. return (L == NULL);
  39. }
  40. int main()
  41. {
  42. LinkList L;
  43. InitList(L);
  44. if(IsEmpty(L)==false)
  45. printf("初始化成功");
  46. if(ListInsert(L, 1, 1))
  47. printf("插入成功");
  48. system("pause");
  49. return 0;
  50. }

 5.2,不带头节点按位序插入:

  1. bool ListInsert(LinkList& L,int i,int e)//在第i个位置插入e
  2. {
  3. if (i < 1)
  4. return false;
  5. if (i == 1)//此处插入第一个节点和其他节点不同,直接与L交互
  6. {
  7. LNode* s = (LNode*)malloc(sizeof(LNode));
  8. s->data = e;
  9. s->next = L;//指向L指向的节点
  10. L = s;//需要更改头结点的指向,比较麻烦
  11. return true;
  12. }
  13. int j = 1;//没有第0个节点
  14. LNode *p;
  15. p= L;//是从第0个节点开始遍历,所以p应该与头节点相同
  16. while (p != NULL && j < i - 1)//找到第i-1的节点
  17. {
  18. p = p->next;
  19. j++;
  20. }
  21. if (p == NULL)//超出链表长度
  22. {
  23. return false;
  24. }
  25. LNode* s = (LNode*)malloc(sizeof(LNode));
  26. s->data = e;
  27. s->next = p->next;
  28. p->next = s;
  29. return true;
  30. }

5.3,指定节点的后插操作:

  1. //在指定节点后插入一个元素
  2. bool InsertNextLNode(LNode *p,int e)//传入节点即可,不需要传入表
  3. {
  4. if (p == NULL)
  5. return false;//节点选择错误
  6. LNode* s = (LNode*)malloc(sizeof(LNode));
  7. if (s == NULL)//内存分配不够
  8. return false;
  9. s->data = e;
  10. s->next = p->next;
  11. p->next = s;
  12. return true;
  13. }

 

5.4前插操作:

在p节点之前插入s节点

思路:无法找到前驱节点,因此可以插在p节点之后,然后将两个节点中的数据调换

  1. bool InsertPriorNode(LNode* p, LNode* s)
  2. {
  3. if (p == NULL || s == NULL)
  4. return false;
  5. s->next = p->next;
  6. p->next = s;
  7. int temp = s->data;
  8. s->data = p->data;
  9. p->data = temp;
  10. return true;
  11. }

 6,链表删除操作:

6.1,带头结点按位序删除第i个节点:

思路:先找到第i-1节点,然后将前一个结点的next指针指向后一个结点的next指针

  1. bool ListDelete(LinkList L, int i, int& e)
  2. {
  3. if (i < 1)
  4. return false;
  5. LNode* p = L;//当前指向结点
  6. int j = 0;
  7. while (p != NULL&&j<i-1) {//找到i-1结点
  8. p = p->next;
  9. j++;
  10. }
  11. if (p == NULL)
  12. return false;
  13. if (p->next== NULL)//需要删除的结点也为空
  14. return false;
  15. LNode* q = p->next;//应当被删除的结点
  16. e = q->data;
  17. p->next = q->next;
  18. free(q);
  19. return true;
  20. }

6.2,指定节点的删除p:

将p的后一个结点复制到p,然后将p的后一个结点释放掉

  1. bool DeleteNode(LNode* p)
  2. {
  3. if (p == NULL)
  4. return false;
  5. LNode* q = p->next;
  6. p->data = p->next->data;
  7. p->next = q->next;
  8. free(q);
  9. return true;
  10. }

注意:如果p是最后一个结点,只能从表头依次寻找p的前驱

7,单链表的查找(带头结点)

7.1按位查找

  1. LNode *GetElem2(LinkList L, int i)
  2. {
  3. if (i < 0)//第位序0返回的是头节点
  4. return NULL;
  5. LNode* p;
  6. p = L;
  7. int j = 0;//带头结点下标从0开始
  8. while (p != NULL && j < i)
  9. {
  10. p = p->next;
  11. j++;
  12. }
  13. return p;
  14. }

回顾:

 

7.2按值查找

  1. LNode* GetElem3(LinkList L, int e)
  2. {
  3. LNode* p=L->next;
  4. while (p != NULL && p->data!=e)//因为头节点中没有数据,所以应该从头节点的下一个结点开始查找
  5. {
  6. p = p->next;
  7. }
  8. return p;
  9. }

求表长:

  1. int GetLength(LinkList L)
  2. {
  3. LNode* p = L; int len = 0;
  4. while (p->next != NULL)
  5. {
  6. p = p->next;
  7. len++;
  8. }
  9. return len;
  10. }

 8,单链表的建立:

8.1尾插法建立单链表

  1. LinkList List_TailInsert(LinkList& L)
  2. {
  3. int a = 0;
  4. L = (LinkList)malloc(sizeof(LNode));//建立头结点
  5. scanf("%d", &a);
  6. LNode* r,*s = L;//r是尾结点
  7. while (a != 9999)//结束标志
  8. {
  9. s = (LNode*)malloc(sizeof(LNode));//放入新节点
  10. s->data = a;
  11. r->next = s;//建立链表连接
  12. r = s;//新的尾结点
  13. scanf("%d", &a);//循环输入数字
  14. }
  15. r->next = NULL;
  16. return L;
  17. }

8.2头插法建立单链表

  1. LinkList List_HeadInsert(LinkList& L)
  2. {
  3. int a = 0;
  4. LNode* s;
  5. L = (LinkList)malloc(sizeof(LNode));//建立头结点
  6. L->next = NULL;//初始化单链表,以防有脏数据
  7. scanf("%d", &a);
  8. while (a != 9999)//结束标志
  9. {
  10. s = (LNode*)malloc(sizeof(LNode));//放入新节点
  11. s->data = a;
  12. s->next= L->next;//建立链表连接
  13. L->next = s;//新的尾结点
  14. scanf("%d", &a);//循环输入数字
  15. }
  16. return L;
  17. }

 尾插法元素排列为顺序,头插法元素排列为逆序,头插法可以用于链表的逆置

9,双链表(带头结点):

9.1定义:

  1. typedef struct DNode {
  2. int data;
  3. struct DNode *prior,* next;
  4. }DNode,*DLinkList;
  5. bool InitDLinkList(DLinkList &L)
  6. {
  7. L = (DNode*)malloc(sizeof(DNode));//分配头结点
  8. if (L == NULL)
  9. return false;
  10. L->prior = NULL;//头结点的前驱节点都为NULL;
  11. L->next = NULL;
  12. return true;
  13. }
  14. int main()
  15. {
  16. DLinkList L;
  17. InitDLinkList(L);
  18. }

9.2插入操作(在p结点后插入s结点)

  1. bool InsertNextDNode(DNode* p, DNode* s)
  2. {
  3. if (p == NULL && s == NULL)
  4. return false;
  5. s->next = p->next;
  6. if (p->next != NULL)//p有后继节点
  7. p->next->prior = s;//则后继节点的前继指针指向s
  8. s->prior = p;
  9. p->next = s;
  10. return true;
  11. }

9.3删除操作(删除p结点的后继节点):

  1. bool DeleteNextDNode(DNode* p)
  2. {
  3. if (p == NULL)
  4. return false;
  5. DNode* q = p->next;
  6. if (q == NULL)
  7. return false;//没有后继节点
  8. p->next = q->next;
  9. if (q->next != NULL)//后继结点不为最后一个结点
  10. q->next->prior = p;//则后继节点的前继指针为s
  11. free(q);
  12. return true;
  13. }

9.4销毁双链表:

  1. void DestoryList(DLinkList &L)//L代表的是链表的头指针
  2. {
  3. while (L->next != NULL)
  4. {
  5. DeleteNextDNode(L);//从表头开始删除
  6. }
  7. free(L);//释放头结点
  8. L = NULL;//头指针指向NULL
  9. }

9.5遍历:

向后遍历:

  1. while(p!=NULL)
  2. {
  3. p=p->next;
  4. }

向前遍历(跳过头结点):

  1. while(p->prior!=NULL)
  2. {
  3. p=p->prior;}

 

10,循环链表:

10.1循环单链表

定义:

  1. typedef struct LNode {
  2. int data;
  3. struct LNode* next;
  4. }LNode,*LinkList;//初始化相同
  5. bool InitList(LinkList& L)
  6. {
  7. L = (LNode*)malloc(sizeof(LNode));//定义头结点
  8. if (L == NULL)//空间分配失败
  9. return false;
  10. L->next = L;//头指针只向自己
  11. return true;
  12. }
  13. bool IsEmpty(LinkList L)
  14. {
  15. if (L->next == L)
  16. return true;
  17. else
  18. return false;
  19. }
  20. bool IsTail(LinkList L,LNode *p)//判断p结点是否为尾结点
  21. {
  22. if (p->next == L)
  23. return true;
  24. else
  25. return false;
  26. }

从一个结点出发,不同于单链表只能找到后续的各个节点,循环单链表可以找到其他任何一个结点 

10.2循环双链表:

初始化:

判断是否为空是否是表尾结点与循环单链表相同,初始化与双链表不同的是:

  1. L->prior=L;
  2. L->next=L;

插入后继结点:

  1. bool InsertNextDNode(DNode* p, DNode* s)
  2. {
  3. s->next = p->next;
  4. p->next->prior = s;//双链表需要判断是否是最后一个结点,循环双链表不需要
  5. s->prior = p;
  6. p->next = s;
  7. return true;
  8. }

删除后继结点:

  1. void DeleteNextDNode(DNode* p)
  2. {
  3. p->next = q->next;
  4. q->next->prior = p;//双链表需要判断是否是最后一个结点,循环双链表不需要
  5. free(q);
  6. }

11,静态链表:用数组的方式实现链表

初始化:

  1. #define MaxSize 10
  2. typedef struct{
  3. int data;
  4. int next;
  5. }SLinkList[MaxSize];
  6. int main(){
  7. SLinkList a;}

12,顺序表与链表的比较 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/439989?site
推荐阅读
相关标签
  

闽ICP备14008679号