单链表完整算法
单链表查找插入删除算法时间效率分析

单链表查找插⼊删除算法时间效率分析单链表查找时间效率分析:
代码:
Lnode *LocateElem_L(LinkList L, ElemType e){
//在线性表L中查找值为 e 的数据元素
//找到,则返回 L 中值为 e 的数据元素的地址
//查找失败返回NULL
p=L->next;
while(p!=NULL && p->data!=e){
p=p->next;
}
return p;
}
上述代码中,循环体⾥的 p=p->next 执⾏多少次?或者说循环执⾏多少次,和我们要查找的元素 e 所在位置有关系如果单链表中第⼀个元素,或者说⾸元结点就是 e ,那么仅执⾏⼀次即可。
如果不是,则顺着指针链,依次向后查找。
因线性链表只能顺序存取,即在查找时要从头指针找起,查找的时间福再度为 O(n)。
插⼊和删除:
因线性链表在插⼊或删除时,不需要移动元素,只要修改指针,⼀般情况下时间复杂度为O(1)。
但是,如果要在单链表中进⾏前插或删除操作,由于要从头查找前驱结点,所耗时间复杂度为O(n)。
进⾏插⼊和删除的操作是常数即便,但是寻找前驱才要O(n)。
写出以单链表为存储结构的一组数据的简单选择排序算法。

写出以单链表为存储结构的一组数据的简单选择排序算法。
以下是单链表存储结构的简单选择排序算法的实现:
```python
def selection_sort(link_list):
n = len(link_list)
for i in range(n):
min_idx = i
for j in range(i+1, n):
if link_list[j] < link_list[min_idx]:
min_idx = j
link_list[i], link_list[min_idx] = link_list[min_idx], link_list[i]
return link_list
```
算法的基本思路是,遍历待排序的链表,找到未排序部分中的最小值,然后将该值与链表的第一个元素交换位置,然后再遍历剩余的元素,继续按照此方法进行排序,直到整个链表都被排序。
在上面的实现中,我们通过 `min_idx` 变量来保存当前未排序部分中的最小值的索引。
在第一次遍历时,min_idx 等于 i,因为在未排序部分中,第一个元素通常是最小的。
在后续的遍历中,我们不断地寻找未排序部分中的最小值,并将其与链表的第一个元素交换位置,最后返回排好序的链表。
单链表的基本算法实验报告

单链表的基本算法实验报告单链表的的基本算法学号:⽇期:⼀、需求分析1.程序的功能(1)程序具备任意选择删除、插⼊、查找数据元素,和求单链表表长等⼏项功能。
(2)当选择删除功能时,从键盘读⼊欲删除的元素位置,按指定位置删除;当选择插⼊功能时,从键盘读⼊新元素值和被插⼊位置,在指定位置插⼊;当选择查找功能时,从键盘读⼊欲查找的元素值,返回其位置序号;当选择求表长功能时,返回该单链表表长的数值。
2.输⼊输出的要求(1)从键盘读⼊⼀组整数,按输⼊顺序形成单链表。
(2)每种操作结束后,都能在屏幕上打印出此时单链表元素的遍历结果。
(3)测试数据从键盘输⼊⼀组若⼲数字使之形成单链表⼆、概要设计1.本程序所⽤的抽象数据类型的定义typedef struct{DataType items[LISTSIZE];int length;}SqList;2.主程序的流程及各程序模块之间的层次关系先定义⼀个顺序表,结构体⾥的⼀位数组为顺序表内容,然后调⽤int InitList(SqList *L)初始化顺序表,然后已键盘输⼊的形式输⼊⼀组⼀维数组,保存到顺序表⾥,次数组以-222作为结束符号,然后调⽤int TraverseList(SqList L)遍历次顺序表,在主函数⾥实⾏do-while在⾥⾯进⾏意选择删除、插⼊、查找数据元素的功能。
删除功能调⽤int ListInsertt(SqList *L),int ListInsertt(SqList *L)⼜调⽤int ListDelete(SqList *L),为嵌套调⽤。
插⼊功能调⽤int ListInsert(SqList *L,int pos,DataType item)此函数。
查找功能调⽤int Find(SqList L);在以上⼦函数中要⽤到int ListEmpty(SqList L)判空函数。
三、详细设计1.采⽤c 语⾔定义相关的数据类型(1)⽤C 语⾔描述的单链表的节点结构 typedef struct Node{DataType data;struct Node *next;}LNode, *PNode,*LinkList; 四、调试分析1.调试中遇到的问题及对问题的解决⽅法在调试过程在运⾏插⼊和查找功能时把位置找错,总是找到正确位置的后⼀个,后来经过仔细阅读课本发现我把书上定义理解错了。
数据结构与算法——单链表的实现及原理

数据结构与算法——单链表的实现及原理1. 单链表的原理 链表是线性表的链式存储⽅式,逻辑上相邻的数据在计算机内的存储位置不必须相邻,那么怎么表⽰逻辑上的相邻关系呢?可以给每个元素附加⼀个指针域,指向下⼀个元素的存储位置。
如图所⽰: 从图中可以看出,每个结点包含两个域:数据域和指针域,指针域存储下⼀个结点的地址,因此指针指向的类型也是结点类型链表的核⼼要素:Ø 每个节点由数据域和指针域组成 Ø 指针域指向下⼀个节点的内存地址。
1.1 结构体定义1 Typedef struct LinkNode2 {3 ElemType data; //节点中存放数据的类型4struct LinkNode* next; //节点中存放下⼀节点的指针5 }LinkList, LinkNode;2. 单链表初始化链表的节点均单向指向下⼀个节点,形成⼀条单向访问的数据链1//单链表的初始化2 typedef struct _LinkNode3 {4int data; //结点的数据域5struct _LinkNode* next; //结点的指针域6 }LinkNode, LinkList; //链表节点、链表78bool InitList(LinkList*& L) //构造⼀个空的单链表 L9 {10 L = new LinkNode; //⽣成新结点作为头结点,⽤头指针 L 指向头结点11if(!L)return false; //⽣成结点失败12 L->next=NULL; //头结点的指针域置空13return true;14 }3. 单链表增加元素 - 单链表前插法插⼊节点的要素就是要找到要插⼊位置的前⼀个节点,将这个节点的Next赋值给新节点,然后将新节点的地址赋值给前⼀个节点的Next便可,任意位置插⼊和前插法均是如此。
1//前插法2bool ListInsert_front(LinkList * &L, LinkNode * node) //参数1 链表指针参数2 要插⼊的节点元素3 {4if (!L || !node) return false; //如果列表或节点为空返回 false5 node->next = L->next; //将头节点指向节点1的地址赋值给要插⼊节点的指针域,使要插⼊的节点先与后部相连6 L->next = node; //将插⼊节点的地址赋值给头结点的指针域,使要插⼊节点与头结点相连78return true;9 }4. 单链表增加元素 - 单链表尾插法1//尾插法2bool ListInsert_back(LinkList*& L, LinkNode* node)3 {4 LinkNode* last = NULL; //创建空指针,5if (!L || !node) return false; //如果列表或节点为空返回 false67 last = L;8while (last->next) last = last->next; //使⽤ last 找到最后⼀个节点910 node->next = NULL; //要插⼊节点由于在尾部,指针域置为 NULL11 last->next = node; //将要插⼊节点的地址赋值给之前的尾部节点的指针域,将要插⼊节点放置到尾部12return true;13 }5. 单链表增加元素 - 单链表任意位置插⼊插⼊节点的要素就是要找到要插⼊位置的前⼀个节点,将这个节点的Next赋值给新节点,然后将新节点的地址赋值给前⼀个节点的Next便可,任意位置插⼊和前插法均是如此。
写一求单链表的结点数目listlength(l)的算法。

写一求单链表的结点数目listlength(l)的算法。
单链表是一种常见的数据结构,它由一系列结点组成,每个结点都有一个指向下一个结点的指针。
求单链表的结点数目listlength(l)是一个常见的问题,下面我们就来讨论一下如何求解这个问题。
首先,我们需要定义一个变量count,用来记录单链表的结点数目。
然后,我们从单链表的头结点开始遍历,每遍历一个结点,count就加1,直到遍历到最后一个结点,count的值就是单链表的结点数目。
具体的算法步骤如下:
(1)定义一个变量count,用来记录单链表的结点数目,初始值为0。
(2)从单链表的头结点开始遍历,每遍历一个结点,count就加1。
(3)直到遍历到最后一个结点,count的值就是单链表的结点数目。
(4)返回count的值。
上述就是求单链表的结点数目listlength(l)的算法,它的时间复杂度为O(n),空间复杂度为O(1),其中n为单链表的结点数目。
总之,求单链表的结点数目listlength(l)是一个常见的问题,上述算法可以有效地解决这个问题,它的时间复杂度和空间复杂度都很低,是一种非常有效的算法。
数据结构___头插法和尾插法建立链表(各分有无头结点)

实验一链表的建立及基本操作方法实现一、【实验目的】1、理解和掌握单链表的类型定义方法和结点生成方法。
2、掌握利用头插法和尾插法建立单链表和显示单链表元素的算法。
3、掌握单链表的查找(按序号)算法。
4、掌握单链表的插入、删除算法。
二、【实验内容】1、利用头插法和尾插法建立一个无头结点单链表,并从屏幕显示单链表元素列表。
2、利用头插法和尾插法建立一个有头结点单链表,并从屏幕显示单链表元素列表。
3、将测试数据结果用截图的方式粘贴在程序代码后面。
重点和难点:尾插法和头插法建立单链表的区别。
建立带头结点和无头结点单链表的区别。
带头结点和无头结点单链表元素显示方法的区别三、【算法思想】1) 利用头插法和尾插法建立一个无头结点单链表链表无头结点,则在创建链表时,初始化链表指针L=NULL。
当用头插法插入元素时,首先要判断头指针是否为空,若为空,则直接将新结点赋给L,新结点next指向空,即L=p,p->next=NULL,若表中已经有元素了,则将新结点的next指向首结点,然后将新结点赋给L即(p->next=L,L=p)。
当用尾插法插入元素时,首先设置一个尾指针tailPointer以便随时指向最后一个结点,初始化tailPointer和头指针一样即tailPointer=L。
插入元素时,首先判断链表是否为空,若为空,则直接将新结点赋给L即L=p,若不为空,else将最后一个元素的next指向新结点即tailPointer->next=p,然后跳出这个if,else语句,将新结点next指向空,并且将tailPointer指向新结点即p->next=NULL,tailPointer=p。
2) 利用头插法和尾插法建立一个有头结点单链表链表有头结点,则在创建链表时,初始化链表指针L->next = NULL。
与无头结点区别在于,判断链表为空是根据L->next是否为空。
用头插法插入元素时,要判断链表是否为空,若为空则将新结点next指向空,作为表尾,若不为空,则直接插入,将新结点next指向头结点next的指向,再将头结点next指向新结点即p->next=L->next,L->next=p。
设计两个有序单链表的合并排序算法

设计两个有序单链表的合并排序算法有序单链表的合并排序,是一种高效的排序算法,可以在较短的时间内对大量数据进行排序。
这种排序算法的核心在于将两个有序的单链表合并成一个有序的单链表,然后再对整个链表进行排序。
合并排序算法的基本原理是分治法。
将需要排序的数组不断地分解成两个子数组,直到每个子数组只包含一个元素为止。
然后再将这些子数组两两合并,直到整个数组被合并成一个有序的数组为止。
这里介绍两个有序单链表的合并排序算法,它们分别是迭代算法和递归算法。
1. 迭代算法迭代算法是一种通用的算法,它的思路是利用循环结构来重复执行一段相同或相似的代码,从而解决一类问题。
对于有序单链表的合并排序,迭代算法的基本思路是将两个有序单链表的元素依次比较,然后将较小的元素加入到新的链表中,直到两个链表中的元素全部被加入到新链表中为止。
以下是迭代算法的具体实现过程:```// 合并两个有序单链表Node* mergeList(Node* head1, Node* head2) { // 新建一个头结点Node* dummy = new Node(-1);// 定义两个指针,分别指向两个链表的头结点 Node* p = head1;Node* q = head2;// 定义一个指针,指向新链表的最后一个节点 Node* curr = dummy;// 循环比较两个链表中的元素while (p != nullptr && q != nullptr) {if (p->val <= q->val) {curr->next = p;p = p->next;} else {curr->next = q;q = q->next;}curr = curr->next;}// 将剩余的元素加入到新链表中curr->next = p != nullptr ? p : q;// 返回新链表的头结点return dummy->next;}// 归并排序Node* mergeSort(Node* head) {if (head == nullptr || head->next == nullptr) {return head;}// 定义两个指针,一个快指针每次走两步,一个慢指针每次走一步 Node* slow = head;Node* fast = head->next;while (fast != nullptr && fast->next != nullptr) {slow = slow->next;fast = fast->next->next;}// 将链表分成两部分Node* head1 = head;Node* head2 = slow->next;slow->next = nullptr;// 分别对两部分链表进行归并排序head1 = mergeSort(head1);head2 = mergeSort(head2);// 合并两个有序单链表return mergeList(head1, head2);}```2. 递归算法递归算法的思想是将一个大问题分解成若干个小问题,然后逐个解决这些小问题,最终得到大问题的解决方案。
数据结构实验报告实现单链表各种基本运算的算法

实验截图(1)void InitList(LinkNode *&L)//初始化线性表{L=(LinkNode *)malloc(sizeof(LinkNode)); //创建头结点L->next=NULL;//单链表置为空表}void DestroyList(LinkNode *&L)//销毁线性表{LinkNode *pre=L,*p=pre->next;实验截图(2)bool GetElem(LinkNode *L,int i,ElemType &e) //求线性表中第i个元素值{ int j=0;if (i<=0) return false;//i错误返回假LinkNode *p=L;//p指向头结点,j置为0(即头结点的序号为0) while (j<i && p!=NULL)//找第i个结点p{ j++;p=p->next;}if (p==NULL)//存在值为e的结点,返回其逻辑序号ireturn(i);}实验截图(3)bool ListInsert(LinkNode *&L,int i,ElemType e) //插入第i个元素{ int j=0;if (i<=0) return false;//i错误返回假LinkNode *p=L,*s;//p指向头结点,j置为0(即头结点的序号为0) while (j<i-1 && p!=NULL)//查找第i-1个结点p{ j++;p=p->next;}}实验截图(4)编写exp2-2.cpp程序包含有关代码//文件名:exp2-2.cpp#include "linklist.cpp"int main(){LinkNode *h;ElemType e;printf("单链表的基本运算如下:\n");printf(" (1)初始化单链表h\n");InitList(h);printf(" (2)依次采用尾插法插入a,b,c,d,e元素\n");return 1;}实验截图(5)运行得到结果实验截图(6)。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
// 包含头文件#include <stdio.h>#include <malloc.h>#include <stdlib.h>// 为结点数据类型和结构体类型起别名typedefint datatype;typedefstructLinkNode{datatype data; // 数据域structLinkNode *next; // 指针域存放下一个结点的地址}LNode,*LinkList;LinkList L; // 单链表的头指针// 1.用头插法创建单链表LinkListCreateListHead(int n){// 创建头结点LNode *L = (LNode *)malloc(sizeof(LNode));L->next = NULL; // 设置指针域为空LinkList p; // p指向新结点for(inti=n;i>0;i--) // 先插入最后一个结点,插入次序与逻辑次序相反{// 生成新结点p = (LNode *)malloc(sizeof(LNode));// 从键盘输入新结点的值printf("请输入要插入第%d结点的值:\n",i);scanf("%d", &p->data);p->next = L->next; // 让L原来的后继结点成为p的后继结点L->next = p; // p成为L新的后继结点}return L; // 返回单链表的头指针}// 2.用尾插法创建单链表LinkListCreateListTail(int n){// 生成头结点L = (LNode *)malloc(sizeof(LNode));L->next = NULL;// 设置指针域为空// p指向新结点,q指向尾结点LinkList p, q = L;// 依次在末尾插入n个结点for(inti=1;i<=n;i++){// 生成新结点pp = (LNode *)malloc(sizeof(LNode));// 从键盘输入新结点的值printf("请输入第%d个结点的值:\n", i);scanf("%d",&p->data);p ->next = NULL; // 新结点(也是尾结点)的指针域为空// 把新结点链接到单链表的末尾q->next = p;// 让q指向新的尾结点q = p;}return L;// 返回单链表的头指针}// 3.显示单链表中的元素值voidShowList(LinkList L){if(L == NULL || L->next==NULL){printf("单链表为空。
\n");return;}LinkList p = L; // 指针p首先指向头结点while(p->next!=NULL) // 当指针p没有到达尾结点时{p = p->next; // 指针后移一个结点printf("%d\n",p->data); // 输出结点数据域的值}}// 4.求单链表的长度(结点的个数)intGetLength (LinkList L){LNode *p=L; /*p 先指向头结点*/int n=0; //n代表除头结点外的结点个数while(p->next != NULL){// 当指针p没有到达尾结点时p=p->next; //指针后挪一个结点n++; //结点个数+1}return n; //返回结点的个数}// 5.按序号查找:在单链表中查找第i个结点LinkListLocateElemByIndex(LinkList L, inti){LinkList p = L; // 指针p先指向头结点,负责后移int j = 0; // j用来计算到达结点的序号if(L==NULL || L->next==NULL) {printf("单链表为空。
\n");return NULL;}// p指针后移的条件:p不是尾结点,而且j<iwhile(p->next!=NULL && j<i){p = p->next; // p指针后移j++; // j递增}if(j==i) // 找到第i个结点时:j==i{return p; // 返回第i个结点的地址}else{return NULL; // 第i个结点不存在,返回NULL }}// 6.按值查找:在单链表中查找值为e的结点LinkListLocateElemByData(LinkList L, datatype e){LinkList p = L; //指针p先指向头结点,负责后移if(L==NULL || L->next==NULL) {printf("单链表为空。
\n");return NULL;}// p指针后移的条件:p不是尾结点,而且p->data!=e while(p->next!=NULL && p->data!=e){p = p->next; // p指针后移}// 找到值为e的结点if(p->data == e){return p; // 返回结点的地址}else{return NULL; // 结点不存在,返回NULL }}// 7.在单链表的第i个位置插入值为e的结点(在第i-1个结点后面插入新结点)voidInsertByIndex(LinkList L, inti, datatype e){LNode *s;LNode *p = LocateElemByIndex(L,i-1);//找到了第i-1个结点if(p!=NULL) {s=(LNode *)malloc(sizeof(LNode));s->data=e;// 修改指针域的两行代码次序不能颠倒s->next=p->next;p->next=s;printf("插入结点完成。
\n");}else {printf("单链表为空或插入位置有误。
\n");}}// 8.在单链表中值为e的结点之后插入新结点voidInsertByDataBehind(LinkList L, datatype e){LNode *s; // s指向新结点,p指向值为e的结点LNode *p = LocateElemByData(L,e);// 找到值为e的结点if(p!=NULL){// 在值为e的结点之后插入新结点s=(LNode *)malloc(sizeof(LNode));// 从键盘输入新结点的值printf("请从键盘输入新结点的值:\n");scanf("%d",&s->data);// 修改指针域的两行代码次序不能颠倒s->next = p->next;p->next = s;printf("插入结点完成。
\n");}else{printf("单链表为空或插入位置有误。
\n");}}// 9.在值为e的结点之前插入voidInsertByDataBefore(LinkListL,datatype e) {LinkList p=L,q,s;while(p->next !=NULL && p->data !=e){q = p;p = p->next;}if(p->data==e){s = (LinkList)malloc(sizeof(LNode));printf("请输入新结点的值:");scanf("%d",&s->data);s->next = p; //s->next=q->next;q->next = s;printf("插入完成。
\n");}else {printf("插入失败。
\n");}}// 10.在单链表中删除第i个结点voidDeleteByIndex(LinkList L, inti){LNode *p = LocateElemByIndex(L,i-1); // p指向第i-1个结点LNode *q = p->next; // q指向第i个结点(待删除结点)if (q!=NULL){p->next = q->next;free(q);}else{printf("单链表为空或删除位置有误。
\n");}}// 11.删除值为e的结点voidDeleteByData(LinkList L, datatype e) {LNode *p=L,*q; //p指向值为e的结点while(p->next!=NULL && p->data!=e) {q=p; //q指向p的前驱结点p=p->next;}if (p->data==e) {q->next = p->next;free (p);printf("删除成功。
\n");} else {printf("删除失败。
\n");}}// 12 删除值为e结点的后继结点voidDeleteByDataBehind(LinkList L, datatype e){LinkList p = L; //指针p先指向头结点,负责后移// p指针后移的条件:p不是尾结点,而且p->data!=e while(p->next!=NULL && p->data!=e){p = p->next; // p指针后移}LNode *q = p->next; // q指向p的后继结点(待删除结点)if (q!=NULL){p->next = q->next;free(q);}else{printf("单链表为空或值为e结点不存在。
\n");}}//主函数void main(){printf("----------------------------------\n");printf("| 1 头插法创建单链表|\n");printf("| 2 尾插法创建单链表|\n");printf("| 3 求单链表长度|\n");printf("| 4 显示单链表中的元素|\n");printf("| 5 查找第i个结点|\n");printf("| 6 查找值为e的结点|\n");printf("| 7 在第i个位置插入|\n");printf("| 8 在值为e结点之后插入|\n");printf("| 9 在值为e结点之前插入|\n"); printf("| 10 删除第i个结点|\n"); printf("| 11 删除值为e的结点|\n"); printf("| 12 删除值为e结点的后继结点|\n"); printf("| 0 退出|\n"); printf("----------------------------------\n");intnum; //选择操作对应的数字int count; //要插入元素的个数int length; //单链表的长度LinkList p; //存放查找结点的首地址inti; //要查找元素的序号datatype e; //要查找元素的值do {printf("请输入要选择操作对应的数字:");scanf("%d", &num);switch(num) {case 1://头插法创建单链表printf("请输入要插入结点的个数:");scanf("%d",&count);L = CreateListHead(count);if (L==NULL){printf("头插法创建失败。