笔记(九)单链表与单循环链表

一 单链表

1.1 概念

单链表:线性表的链式存储

线性表:一对一的关系

链式存储:不需要在内存中开辟一段连续的内存的空间,所以每一个数据不再是一个基本数据,而是由两部分组成,数据域和指针域,数据域保存数据,指针域保存下一个结点的地址。

单链表:就是单向链表,前者结点可以找到后者结点,但是后者无法找到前者。

1.2 单链表的操作

1.2.1 定义结点结构体

 

C

自动换行

#ifndef _LINKLIST_H_
#define _LINKLIST_H_
#include <stdio.h>
#include <stdlib.h>
//定义数据类型
typedef int DataType;
//定义结点结构体
typedef struct linklist
{
    DataType data; //数据域
    struct linklist *next; //指针域,为了能够操作后面结点
                            //所以指针的类型为当前结构体的类型
}linklist;
endif

1.2.2 创建一个空的单链表

//创建一个空的单链表 linklist* LinkListCreate() {     //定义一个头结点,在堆区开辟空间     linklist *head = (linklist *)malloc(sizeof(linklist));     //初始化指针域标识为空     head->next = NULL;     return head; }

1.2.3 头插法插入数据

//头插法插入数据 void LinkListInsertHead(linklist *head,DataType value) {     //开辟空间,分配一个新的结点     linklist *tmp = (linklist *)malloc(sizeof(linklist));     tmp->data = value;     tmp->next = NULL;     //将要插入的结点的指针域指向第一个结点     //第一个结点的地址:head->next     //新插入结点的指针域:tmp->next     tmp->next = head->next;     //头结点的指针域保存要插入的结点的地址     //头结点的指针域:head->next     //新插入结点的地址:tmp     head->next = tmp;     return; }

1.2.4 遍历单链表

//遍历单链表 void LinkListPrint(linklist *head) {     //定义一个指针保存第一个结点的地址     linklist *p = head->next;     while(p != NULL)     {         //打印数据         printf("%d ",p->data);         //p指向下一个结点(p保存下一个结点的地址)         p = p->next;     }     putchar(10); }

1.2.5 尾插法插入数据

//尾插法插入数据 void LinkListInsertTail(linklist *head,DataType value) { //申请空间,分配结点结构体 linklist *tmp = (linklist *)malloc(sizeof(linklist)); tmp->data = value; tmp->next = NULL; //找到最后一个结点 linklist *p = head; while(p->next != NULL) { p = p->next; } //将新插入的结点保存在最后一个结点的后面 p->next = tmp; //将新插入的结点的指针域指向NULL tmp->next = NULL; return; }

1.2.6 判断单链表是否为空

//判断单链表是否为空 int LinkListIsEmpty(linklist *head) { return head->next == NULL ? 1 : 0; }

1.2.7 头删法删除数据(返回删除的数据)

//头删法,返回删除的数据 DataType LinkListDeleteHead(linklist *head) { if(LinkListIsEmpty(head)) { printf("删除失败,单链表为空!\n"); return (DataType)-1; } DataType value = head->next->data; linklist *tmp = head->next; head->next = head->next->next; free(tmp); tmp = NULL; return value; }

1.2.8 按照数据修改数据

void LinkListUpdate(linklist *head,DataType OldValue,DataType NewValue) { if(LinkListIsEmpty(head)) { printf("修改数据失败,链表为空"); return; } linklist *p = head; int flags = 0; while(p->next != NULL) { p = p->next; if(p->data == OldValue) { p->data = NewValue; flags = 1; } } if(flags == 0) { printf("数据%d不存在,修改失败\n",OldValue); } return; }

1.2.9 按照位置查找数据

//按照位置查找数据 DataType LinklistSearchData(linklist *head,int pos) { if(LinkListIsEmpty(head)) { printf("查找失败,链表为空!\n"); } if(pos < 1) { printf("位置有误!\n"); } linklist *p = head; int i; for(i = 1; i <= pos;i++) { if(p == NULL) { printf("输入位置有误!\n"); return (DataType)-1; } p = p->next; } return p->data; }

1.2.10 按照数据查找位置

//按照数据查找位置 int LinkListSearchPos(linklist *head,DataType value) { if(LinkListIsEmpty(head)) { printf("查找位置失败,链表为空!\n"); return (DataType)-1; } linklist *p = head; int pos = 0; while(p->next != NULL) { p = p->next; pos++; if(p->data == value) { return pos; } } printf("查找位置失败!\n"); return (DataType)-1; }

1.2.11 按照位置插入数据

//按照位置插入数据 void LinkListInsertByPos(linklist *head,int pos,DataType value) { if(pos < 1) { printf("按照位置插入数据有误"); return; } linklist *tmp = (linklist *)malloc(sizeof(linklist)); tmp->data = value; tmp->next = NULL; if(LinkListIsEmpty(head)) { tmp->next = head->next; head->next = tmp; } else { int i; linklist *p = head; for(i = 0 ; i < pos ;i++) { if(p->next == NULL) { printf("位置有误!\n"); return; } p = p->next; } tmp->next = p->next; p->next = tmp; } }

1.2.12 直接插入排序

//直接插入排序 void LinkListInsertSort(linklist *head,DataType value) { linklist *tmp = (linklist *)malloc(sizeof(linklist)); tmp->data = value; tmp->next = NULL; linklist *p = head; while(p->next != NULL && p->next->data < tmp->data) { p = p->next; } tmp->next = p->next; p->next = tmp; }

练习:实现单链表的反转

h1: 10->20->30->40->NULL

......

h2:40->30->20->10->NULL

//单链表翻转 void LinkListReverse(linklist *head) { if(LinkListIsEmpty(head)) { printf("链表为空,无需翻转!\n"); return; } linklist *h1 = LinkListCreate(); linklist *p = head; DataType value; while(p->next != NULL) { value = LinkListDeleteHead(head); LinkListInsertHead(h1,value); } head->next= h1->next; } //单链表翻转2 void LinkListReverse2(linklist *head) { if(LinkListIsEmpty(head)) { printf("链表为空,无需翻转!\n"); return; } //定义两个指针变量来执行链表的翻转 linklist *p = NULL, *q = NULL; //p指针保存第一个结点的地址 p = head->next; //头结点指向NULL head->next = NULL; while(p != NULL) { //q指针保存p指向的结点的地址 q = p; p = p->next; //头插法将q插入到head链表中 q->next = head->next; head->next = q; } }

练习:单链表的整表删除

//单链表的整表删除 void LinkListClear(linklist *head) { linklist *p = NULL,*q = NULL; p = head->next; while(p != NULL) { q = p->next; free(p); p = q; } head->next = NULL; }

1.3 整体代码

//头文件 #ifndef _LINKLIST_H_ #define _LINKLIST_H_ #include <stdio.h> #include <stdlib.h> //定义数据类型 typedef int DataType; //定义结点结构体 typedef struct linklist {     DataType data; //数据域     struct linklist *next; //指针域,为了能够操作后面结点                             //所以指针的类型为当前结构体的类型 }linklist; //创建一个空的单链表 linklist* LinkListCreate(); //头插法插入数据 void LinkListInsertHead(linklist *head,DataType value); //遍历单链表 void LinkListPrint(linklist *head); //尾插法插入数据 void LinkListInsertTail(linklist *head,DataType value); //判断单链表是否为空 int LinkListIsEmpty(linklist *head); //头删法,返回删除的数据 DataType LinkListDeleteHead(linklist *head); //按照数据修改数据 void LinkListUpdate(linklist *head,DataType OldValue,DataType NewValue); //按照位置查找数据 DataType LinklistSearchData(linklist *head,int pos); //按照数据查找位置 int LinkListSearchPos(linklist *head,DataType value); //按照位置插入数据 void LinkListInsertByPos(linklist *head,int pos,DataType value); //直接插入排序 void LinkListInsertSort(linklist *head,DataType value); //单链表翻转 void LinkListReverse(linklist *head); //单链表翻转2 void LinkListReverse2(linklist *head); //单链表的整表删除 void LinkListClear(linklist *head); #endif

//功能函数 #include "linklist.h" //创建一个空的单链表 linklist* LinkListCreate() {     //定义一个头结点,在堆区开辟空间     linklist *head = (linklist *)malloc(sizeof(linklist));     //初始化指针域标识为空     head->next = NULL;     return head; } //头插法插入数据 void LinkListInsertHead(linklist *head,DataType value) {     //开辟空间,分配一个新的结点     linklist *tmp = (linklist *)malloc(sizeof(linklist));     tmp->data = value;     tmp->next = NULL;     //将要插入的结点的指针域指向第一个结点     //第一个结点的地址:head->next     //新插入结点的指针域:tmp->next     tmp->next = head->next;     //头结点的指针域保存要插入的结点的地址     //头结点的指针域:head->next     //新插入结点的地址:tmp     head->next = tmp;     return; } //遍历单链表 void LinkListPrint(linklist *head) {     //定义一个指针保存第一个结点的地址     linklist *p = head->next;     while(p != NULL)     {         //打印数据         printf("%d ",p->data);         //p指向下一个结点(p保存下一个结点的地址)         p = p->next;     }     putchar(10); } //尾插法插入数据 void LinkListInsertTail(linklist *head,DataType value) {     //申请空间,分配结点结构体     linklist *tmp = (linklist *)malloc(sizeof(linklist));     tmp->data = value;     tmp->next = NULL;     //找到最后一个结点     linklist *p = head;     while(p->next != NULL)     {         p = p->next;     }     //将新插入的结点保存在最后一个结点的后面     p->next = tmp;     //将新插入的结点的指针域指向NULL     tmp->next = NULL;     return; } //判断单链表是否为空 int LinkListIsEmpty(linklist *head) {     return head->next == NULL ? 1 : 0; } //头删法,返回删除的数据 DataType LinkListDeleteHead(linklist *head) {     if(LinkListIsEmpty(head))     {         printf("删除失败,单链表为空!\n");         return (DataType)-1;     }     DataType value = head->next->data;     linklist *tmp = head->next;     head->next = head->next->next;     free(tmp);     tmp = NULL;     return value; } //按照数据修改数据 void LinkListUpdate(linklist *head,DataType OldValue,DataType NewValue) {     if(LinkListIsEmpty(head))     {         printf("修改数据失败,链表为空");         return;     }     linklist *p = head;     int flags = 0;     while(p->next != NULL)     {         p = p->next;         if(p->data == OldValue)         {             p->data = NewValue;             flags = 1;         }     }     if(flags == 0)     {         printf("数据%d不存在,修改失败\n",OldValue);     }     return; } //按照位置查找数据 DataType LinklistSearchData(linklist *head,int pos) {     if(LinkListIsEmpty(head))     {         printf("查找失败,链表为空!\n");     }     if(pos < 1)     {         printf("位置有误!\n");     }     linklist *p = head;     int i;     for(i = 1; i <= pos;i++)     {         if(p == NULL)         {             printf("输入位置有误!\n");             return (DataType)-1;         }         p = p->next;     }     return p->data; } //按照数据查找位置 int LinkListSearchPos(linklist *head,DataType value) {     if(LinkListIsEmpty(head))     {         printf("查找位置失败,链表为空!\n");         return (DataType)-1;     }     linklist *p = head;     int pos = 0;     while(p->next != NULL)     {         p = p->next;         pos++;         if(p->data == value)         {             return pos;         }     }     printf("查找位置失败!\n");     return (DataType)-1; } //按照位置插入数据 void LinkListInsertByPos(linklist *head,int pos,DataType value) {     if(pos < 1)     {         printf("按照位置插入数据有误");         return;     }     linklist *tmp = (linklist *)malloc(sizeof(linklist));     tmp->data = value;     tmp->next = NULL;     if(LinkListIsEmpty(head))     {         tmp->next = head->next;         head->next = tmp;     }     else     {         int i;         linklist *p = head;         for(i = 0 ; i < pos ;i++)         {             if(p->next == NULL)             {                 printf("位置有误!\n");                 return;             }             p = p->next;         }         tmp->next = p->next;         p->next = tmp;     } } //直接插入排序 void LinkListInsertSort(linklist *head,DataType value) {     linklist *tmp = (linklist *)malloc(sizeof(linklist));     tmp->data = value;     tmp->next = NULL;     linklist *p = head;     while(p->next != NULL && p->next->data < tmp->data)     {         p = p->next;     }     tmp->next = p->next;     p->next = tmp; } //单链表翻转 void LinkListReverse(linklist *head) {     if(LinkListIsEmpty(head))     {         printf("链表为空,无需翻转!\n");         return;     }     linklist *h1 = LinkListCreate();     linklist *p = head;     DataType value;     while(p->next != NULL)     {         value = LinkListDeleteHead(head);         LinkListInsertHead(h1,value);     }     head->next= h1->next; } //单链表翻转2 void LinkListReverse2(linklist *head) {     if(LinkListIsEmpty(head))     {         printf("链表为空,无需翻转!\n");         return;     }     //定义两个指针变量来执行链表的翻转     linklist *p = NULL, *q = NULL;     //p指针保存第一个结点的地址     p = head->next;     //头结点指向NULL     head->next = NULL;     while(p != NULL)     {         //q指针保存p指向的结点的地址         q = p;         p = p->next;         //头插法将q插入到head链表中         q->next = head->next;         head->next = q;     } } //单链表的整表删除 void LinkListClear(linklist *head) {     linklist *p = NULL,*q = NULL;     p = head->next;     while(p != NULL)     {         q = p->next;         free(p);         p = q;     }     head->next = NULL; }

//main.c #include "linklist.h" int main(int argc, char const *argv[]) {     linklist *head = LinkListCreate();     int i;     for(i= 0 ; i < 10;i++)     {         LinkListInsertHead(head,i + 1);     }     LinkListPrint(head);     for(; i < 20;i++)     {         LinkListInsertTail(head,i + 1);     }     LinkListPrint(head);     for(i = 0 ; i < 5;i++)     {         LinkListDeleteHead(head);     }     LinkListPrint(head);     LinkListUpdate(head,11,999);     LinkListPrint(head);     printf("位置4的数据为%d\n",LinklistSearchData(head,4));     printf("数据为999的位置为%d\n",LinkListSearchPos(head,9999));     LinkListInsertByPos(head,3,777);     LinkListPrint(head);     LinkListInsertSort(head,9);     LinkListInsertSort(head,188);     LinkListInsertSort(head,12);     LinkListInsertSort(head,0);     LinkListInsertSort(head,6);     LinkListPrint(head);     LinkListReverse(head);     LinkListPrint(head);     LinkListReverse2(head);     LinkListPrint(head);     LinkListClear(head);     LinkListInsertSort(head,9);     LinkListInsertSort(head,188);     LinkListInsertSort(head,12);     LinkListInsertSort(head,0);     LinkListInsertSort(head,6);     LinkListPrint(head);     return 0; }

二 单向循环链表

2.1 概念

2.2 单向循环链表的操作

定义结点结构体

创建一个空的单向循环链表

插入数据

打印数据

删除头结点

打印数据

2.2.1 定义结点结构体

//定义数据类型 typedef int DataType; //定义结点结构体 typedef struct looplist { DataType data; struct looplist *next; }looplist;

2.2.2 创建空的单向循环链表

//创建一个空的单向循环链表 looplist* LoopListCreate() { looplist *head = (looplist *)malloc(sizeof(looplist)); //初始状态就为循环 //头结点的指针域保存头结点的地址 head->next = head; return head; }

2.2.3 插入数据

//插入数据 void LoopListInsert(looplist *head,DataType value) { looplist *tmp = (looplist *)malloc(sizeof(looplist)); tmp->next = NULL; tmp->data = value; tmp->next = head->next; head->next = tmp; return; }

2.2.4 遍历单向循环链表

//遍历单向循环链表 void LoopListPrint(looplist *head) { looplist *p = head; while(p->next != head) { p = p->next; printf("%d ",p->data); } putchar(10); }

2.2.5 删除头结点

//删除头结点 looplist* LoopListCutHead(looplist *head) { looplist *p = head; while(p->next != head) { p = p->next; } p->next = head->next; free(head); head = NULL; return p->next; }

2.2.6 去头结点遍历

//去头结点遍历单向循环链表 void LoopListPrint2(looplist *head) { looplist *p = head; while(p->next != head) { printf("%d ",p->data); p = p->next; } printf("%d\n",p->data); }

2.3 作业 joseph问题

设编号分别为:1,2...n个人围成一圈,约定序号为k(1

例如:n = 8,k = 3,m = 4

void Joseph(int n,int k,int m) { if(n < k || n < m) { printf("k或者M输入有误!,k = %d,m = %d\n",k,m); return; } //创建一个空的单向循环链表 looplist *h1 = LoopListCreate(); int i; for(i = n ; i >=1;i--) { LoopListInsert(h1,i); } h1 = LoopListCutHead(h1); LoopListPrint2(h1); //找到编号为k的人 for(i = 1; i < k;i++) { h1 = h1->next; } //循环删除数到m的那个结点 looplist *tmp = NULL; while(h1->next != h1) { //为了删除指定的结点,所以h1指针保存数到m-1的结点 for(i = 1; i < m-1;i++) { h1 = h1->next; } //删除h1后面的结点 tmp = h1->next; h1->next = tmp->next; printf("%d ",tmp->data); free(tmp); tmp = NULL; //从下一个结点开始数数 h1 = h1->next; } printf("%d\n",h1->data); free(h1); h1 = NULL; return; }

2.4 完整代码

looplist.h #ifndef _LOOPLIST_H_ #define _LOOPLIST_H_ #include <stdio.h> #include <stdlib.h> //定义数据类型 typedef int DataType; //定义结点结构体 typedef struct looplist { DataType data; struct looplist *next; }looplist; //创建一个空的单向循环链表 looplist* LoopListCreate(); //插入数据 void LoopListInsert(looplist *head,DataType value); //遍历单链表 void LoopListPrint(looplist *head); //删除头结点 looplist* LoopListCutHead(looplist *head); //去头结点遍历单向循环链表 void LoopListPrint2(looplist *head); #endif

//main.c #include "looplist.h" int main(int argc, char const *argv[]) { looplist *head = LoopListCreate(); int i; for(i = 0 ; i < 10;i++) { LoopListInsert(head,i + 1); } LoopListPrint(head); head = LoopListCutHead(head); LoopListPrint2(head); return 0; }

//looplist.c #include "looplist.h" //创建一个空的单向循环链表 looplist* LoopListCreate() { looplist *head = (looplist *)malloc(sizeof(looplist)); //初始状态就为循环 //头结点的指针域保存头结点的地址 head->next = head; return head; } //插入数据 void LoopListInsert(looplist *head,DataType value) { looplist *tmp = (looplist *)malloc(sizeof(looplist)); tmp->next = NULL; tmp->data = value; tmp->next = head->next; head->next = tmp; return; } //遍历单向循环链表 void LoopListPrint(looplist *head) { looplist *p = head; while(p->next != head) { p = p->next; printf("%d ",p->data); } putchar(10); } //删除头结点 looplist* LoopListCutHead(looplist *head) { looplist *p = head; while(p->next != head) { p = p->next; } p->next = head->next; free(head); head = NULL; return p->next; } //去头结点遍历单向循环链表 void LoopListPrint2(looplist *head) { looplist *p = head; while(p->next != head) { printf("%d ",p->data); p = p->next; } printf("%d\n",p->data); }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值