数据结构与算法-双向循环链表 - 图1

准备条件

  1. #define ERROR 0
  2. #define TRUE 1
  3. #define FALSE 0
  4. #define OK 1
  5. #define MAXSIZE 20 /* 存储空间初始分配量 */
  6. typedef int Status;/* Status是函数的类型,其值是函数结果状态代码,如OK等 */
  7. typedef int ElemType;/* ElemType类型根据实际情况而定,这里假设为int */
  8. //定义结点
  9. typedef struct Node{
  10. ElemType data;
  11. struct Node *prior;
  12. struct Node *next;
  13. }Node;
  14. typedef struct Node * LinkList;

双向链表学习

双向链表创建

截屏2020-08-21 下午3.16.25.png
代码实现:

  1. //5.1 创建双向链接
  2. Status createLinkList(LinkList *L){
  3. //*L 指向头结点
  4. *L = (LinkList)malloc(sizeof(Node));
  5. if (*L == NULL) return ERROR;
  6. (*L)->prior = NULL;
  7. (*L)->next = NULL;
  8. (*L)->data = -1;
  9. //新增数据
  10. LinkList p = *L;
  11. for(int i=0; i < 10;i++){
  12. //1.创建1个临时的结点
  13. LinkList temp = (LinkList)malloc(sizeof(Node));
  14. temp->prior = NULL;
  15. temp->next = NULL;
  16. temp->data = i;
  17. //2.为新增的结点建立双向链表关系
  18. //① temp 是p的后继
  19. p->next = temp;
  20. //② temp 的前驱是p
  21. temp->prior = p;
  22. //③ p 要记录最后的结点的位置,方便下一次插入
  23. p = p->next;
  24. }
  25. return OK;
  26. }


打印链表:**

  1. //5.2 打印循环链表的元素
  2. void display(LinkList L){
  3. LinkList temp = L->next;
  4. if(temp == NULL){
  5. printf("打印的双向链表为空!\n");
  6. return;
  7. }
  8. while (temp) {
  9. printf("%d ",temp->data);
  10. temp = temp->next;
  11. }
  12. printf("\n");
  13. }

双向链表插入

截屏2020-08-21 下午3.18.18.png
截屏2020-08-21 下午3.19.32.png

代码实现:

  1. //5.3 双向链表插入元素
  2. Status ListInsert(LinkList *L, int i, ElemType data){
  3. //1. 插入的位置不合法 为0或者为负数
  4. if(i < 1) return ERROR;
  5. //2. 新建结点
  6. LinkList temp = (LinkList)malloc(sizeof(Node));
  7. temp->data = data;
  8. temp->prior = NULL;
  9. temp->next = NULL;
  10. //3.将p指向头结点!
  11. LinkList p = *L;
  12. //4. 找到插入位置i直接的结点
  13. for(int j = 1; j < i && p;j++)
  14. p = p->next;
  15. //5. 如果插入的位置超过链表本身的长度
  16. if(p == NULL){
  17. return ERROR;
  18. }
  19. //6. 判断插入位置是否为链表尾部;
  20. if (p->next == NULL) {
  21. p->next = temp;
  22. temp->prior = p;
  23. }else
  24. {
  25. //1️⃣ 将p->next 结点的前驱prior = temp
  26. p->next->prior = temp;
  27. //2️⃣ 将temp->next 指向原来的p->next
  28. temp->next = p->next;
  29. //3️⃣ p->next 更新成新创建的temp
  30. p->next = temp;
  31. //4️⃣ 新创建的temp前驱 = p
  32. temp->prior = p;
  33. }
  34. return OK;
  35. }

双向链表删除

截屏2020-08-21 下午3.20.46.png
代码实现:

  1. //5.4 删除双向链表指定位置上的结点
  2. Status ListDelete(LinkList *L, int i, ElemType *e){
  3. int k = 1;
  4. LinkList p = (*L);
  5. //1.判断双向链表是否为空,如果为空则返回ERROR;
  6. if (*L == NULL) {
  7. return ERROR;
  8. }
  9. //2. 将指针p移动到删除元素位置前一个
  10. while (k < i && p != NULL) {
  11. p = p->next;
  12. k++;
  13. }
  14. //3.如果k>i 或者 p == NULL 则返回ERROR
  15. if (k>i || p == NULL) {
  16. return ERROR;
  17. }
  18. //4.创建临时指针delTemp 指向要删除的结点,并将要删除的结点的data 赋值给*e,带回到main函数
  19. LinkList delTemp = p->next;
  20. *e = delTemp->data;
  21. //5. p->next 等于要删除的结点的下一个结点
  22. p->next = delTemp->next;
  23. //6. 如果删除结点的下一个结点不为空,则将将要删除的下一个结点的前驱指针赋值p;
  24. if (delTemp->next != NULL) {
  25. delTemp->next->prior = p;
  26. }
  27. //7.删除delTemp结点
  28. free(delTemp);
  29. return OK;
  30. }

双向链表删除指定的元素

截屏2020-08-21 下午3.22.53.png
代码实现:

  1. //5.5 删除双向链表指定的元素
  2. Status LinkListDeletVAL(LinkList *L, int data){
  3. LinkList p = *L;
  4. //1.遍历双向循环链表
  5. while (p) {
  6. //2.判断当前结点的数据域和data是否相等,若相等则删除该结点
  7. if (p->data == data) {
  8. //修改被删除结点的前驱结点的后继指针,参考图上步骤1️⃣
  9. p->prior->next = p->next;
  10. //修改被删除结点的后继结点的前驱指针,参考图上步骤2️⃣
  11. if(p->next != NULL){
  12. p->next->prior = p->prior;
  13. }
  14. //释放被删除结点p
  15. free(p);
  16. //退出循环
  17. break;
  18. }
  19. //没有找到该结点,则继续移动指针p
  20. p = p->next;
  21. }
  22. return OK;
  23. }

双向链表查找元素

  1. int selectElem(LinkList L,ElemType elem){
  2. LinkList p = L->next;
  3. int i = 1;
  4. while (p) {
  5. if (p->data == elem) {
  6. return i;
  7. }
  8. i++;
  9. p = p->next;
  10. }
  11. return -1;
  12. }

双向链表更新结点

  1. Status replaceLinkList(LinkList *L,int index,ElemType newElem){
  2. LinkList p = (*L)->next;
  3. for (int i = 1; i < index; i++) {
  4. p = p->next;
  5. }
  6. p->data = newElem;
  7. return OK;
  8. }

双向循环链表学习

双向循环链表

截屏2020-08-21 下午3.25.55.png
代码实现:

  1. //6.1 双向循环链表初始化
  2. Status creatLinkList(LinkList *L){
  3. *L = (LinkList)malloc(sizeof(Node));
  4. if (*L == NULL) {
  5. return ERROR;
  6. }
  7. (*L)->next = (*L);
  8. (*L)->prior = (*L);
  9. //新增数据
  10. LinkList p = *L;
  11. for(int i=0; i < 10;i++){
  12. //1.创建1个临时的结点
  13. LinkList temp = (LinkList)malloc(sizeof(Node));
  14. temp->data = i;
  15. //2.为新增的结点建立双向链表关系
  16. //① temp 是p的后继
  17. p->next = temp;
  18. //② temp 的前驱是p
  19. temp->prior = p;
  20. //③ temp的后继是*L
  21. temp->next = (*L);
  22. //④ p 的前驱是新建的temp
  23. p->prior = temp;
  24. //⑤ p 要记录最后的结点的位置,方便下一次插入
  25. p = p->next;
  26. }
  27. return OK;
  28. }

双向循环列表插入结点

截屏2020-08-21 下午3.27.32.png
代码实现:

  1. //6.2 双向循环链表插入元素
  2. /*当插入位置超过链表长度则插入到链表末尾*/
  3. Status LinkListInsert(LinkList *L, int index, ElemType e){
  4. //1. 创建指针p,指向双向链表头
  5. LinkList p = (*L);
  6. int i = 1;
  7. //2.双向循环链表为空,则返回error
  8. if(*L == NULL) return ERROR;
  9. //3.找到插入前一个位置上的结点p
  10. while (i < index && p->next != *L) {
  11. p = p->next;
  12. i++;
  13. }
  14. //4.如果i>index 则返回error
  15. if (i > index) return ERROR;
  16. //5.创建新结点temp
  17. LinkList temp = (LinkList)malloc(sizeof(Node));
  18. //6.temp 结点为空,则返回error
  19. if (temp == NULL) return ERROR;
  20. //7.将生成的新结点temp数据域赋值e.
  21. temp->data = e;
  22. //8.将结点temp 的前驱结点为p;
  23. temp->prior = p;
  24. //9.temp的后继结点指向p->next;
  25. temp->next = p->next;
  26. //10.p的后继结点为新结点temp;
  27. p->next = temp;
  28. //如果temp 结点不是最后一个结点
  29. if (*L != temp->next) {
  30. //11.temp节点的下一个结点的前驱为temp 结点
  31. temp->next->prior = temp;
  32. }else{
  33. (*L)->prior = temp;
  34. }
  35. return OK;
  36. }

打印表信息:

  1. //6.3 遍历双向循环链表
  2. Status Display(LinkList L){
  3. if (L == NULL) {
  4. printf("打印的双向循环链表为空!\n\n");
  5. return ERROR;
  6. }
  7. printf("双向循环链表内容: ");
  8. LinkList p = L->next;
  9. while (p != L) {
  10. printf("%d ",p->data);
  11. p = p->next;
  12. }
  13. printf("\n\n");
  14. return OK;
  15. }

双向循环列表删除结点

截屏2020-08-21 下午3.29.34.png
代码实现:

  1. //6.4 双向循环链表删除结点
  2. Status LinkListDelete(LinkList *L,int index,ElemType *e){
  3. int i = 1;
  4. LinkList temp = (*L)->next;
  5. if (*L == NULL) {
  6. return ERROR;
  7. }
  8. //①.如果删除到只剩下首元结点了,则直接将*L置空;
  9. if(temp->next == *L){
  10. free(*L);
  11. (*L) = NULL;
  12. return OK;
  13. }
  14. //1.找到要删除的结点
  15. while (i < index) {
  16. temp = temp->next;
  17. i++;
  18. }
  19. //2.给e赋值要删除结点的数据域
  20. *e = temp->data;
  21. //3.修改被删除结点的前驱结点的后继指针 图1️⃣
  22. temp->prior->next = temp->next;
  23. //4.修改被删除结点的后继结点的前驱指针 图2️⃣
  24. temp->next->prior = temp->prior;
  25. //5. 删除结点temp
  26. free(temp);
  27. return OK;
  28. }

顺序表和链表的比较

截屏2020-08-21 下午3.30.23.png

线性表总结

截屏2020-08-21 下午3.31.12.png