数据结构 单链表详解
数据结构课程设计-单链表

目录1 选题背景 (1)2 方案与论证 (1)2。
1 链表的概念和作用 (1)2。
3 算法的设计思想 (2)2。
4 相关图例 (3)2.4.1 单链表的结点结构 (3)2.4。
2 算法流程图 (3)3 实验结果 (4)3.1 链表的建立 (4)3.2 单链表的插入 (4)3.3 单链表的输出 (5)3.4 查找元素 (5)3。
5 单链表的删除 (5)3。
6 显示链表中的元素个数(计数) (5)4 结果分析 (6)4。
1 单链表的结构 (6)4。
2 单链表的操作特点 (6)4。
2。
1 顺链操作技术 (6)4.2。
2 指针保留技术 (6)4。
3 链表处理中的相关技术 (6)5 设计体会及今后的改进意见 (6)参考文献 (8)附录代码: (8)1 选题背景陈火旺院士把计算机60多年的发展成就概括为五个“一”:开辟一个新时代-—--信息时代,形成一个新产业-—-—信息产业,产生一个新科学—---计算机科学与技术,开创一种新的科研方法-—--计算方法,开辟一种新文化---—计算机文化,这一概括深刻影响了计算机对社会发展所产生的广泛而深远的影响。
数据结构和算法是计算机求解问题过程的两大基石。
著名的计算机科学家P.Wegner指出,“在工业革命中其核心作用的是能量,而在计算机革命中其核心作用的是信息”.计算机科学就是“一种关于信息结构转换的科学”.信息结构(数据结构)是计算机科学研究的基本课题,数据结构又是算法研究的基础。
2 方案与论证2。
1 链表的概念和作用链表是一种链式存储结构,链表属于线性表,采用链式存储结构,也是常用的动态存储方法。
链表中的数据是以结点来表示的,每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。
以“结点的序列”表示线性表称作线性链表(单链表)单链表是链式存取的结构,为找第 i 个数据元素,必须先找到第 i-1 个数据元素。
数据结构单链表实验报告

数据结构单链表实验报告一、实验目的本次实验的主要目的是深入理解和掌握数据结构中的单链表概念、原理和操作方法,通过实际编程实现单链表的创建、插入、删除、查找等基本操作,提高对数据结构的实际应用能力和编程技能。
二、实验环境本次实验使用的编程语言为C++,编程工具为Visual Studio 2019。
三、实验原理单链表是一种常见的数据结构,它由一系列节点组成,每个节点包含数据域和指针域。
指针域用于指向下一个节点,从而形成链表的链式结构。
单链表的优点是可以动态地分配内存,灵活地插入和删除节点,但其缺点是访问特定位置的节点需要从头开始遍历,时间复杂度较高。
四、实验内容(一)单链表的创建创建单链表的基本思路是依次创建节点,并将节点通过指针链接起来。
以下是创建单链表的代码实现:```cppinclude <iostream>using namespace std;//定义链表节点结构体struct ListNode {int data;ListNode next;ListNode(int x) : data(x), next(NULL) {}};//创建单链表ListNode createList(){int num, value;cout <<"请输入节点个数: ";cin >> num;ListNode head = NULL;ListNode tail = NULL;for (int i = 0; i < num; i++){cout <<"请输入第"<< i + 1 <<"个节点的值: ";cin >> value;if (head == NULL) {head = newNode;tail = newNode;} else {tail>next = newNode;tail = newNode;}}return head;}```(二)单链表的插入操作单链表的插入操作可以分为在表头插入、在表尾插入和在指定位置插入。
单链表存储结构的概念

单链表存储结构的概念单链表(Singly Linked List)是一种常见的线性数据结构,用于存储一系列具有相同类型的元素。
它由一组称为节点(Node)的对象组成,每个节点包含了数据元素和一个指向下一个节点的引用(通常称为指针或链接)。
单链表的存储结构的概念如下:1.节点(Node):每个节点包含两个部分,一个是数据元素,用于存储实际的数据值;另一个是指向下一个节点的链接(指针),用于指示下一个节点的位置。
2.头节点(Head):单链表的起始节点称为头节点,它不包含实际的数据元素,只是用于标识整个链表的起点。
头节点通常是第一个具有数据元素的节点的前一个节点。
3.尾节点(Tail):单链表的结束节点称为尾节点,它是最后一个具有数据元素的节点。
尾节点的链接通常为空(null),表示链表的结束。
4.链表的连接方式:通过每个节点的链接(指针),单链表中的节点按顺序串联在一起,形成链表结构。
通过链接,可以迅速访问到链表中的下一个节点。
单链表的存储结构具有以下特点和优势:•动态性:单链表的长度可以在运行时动态改变,不需要事先指定链表的大小。
•灵活性:可以在链表中任意位置进行插入和删除操作,不需要移动其他节点的位置。
•存储效率:相对于数组,单链表可以节省存储空间,因为它不需要预留固定大小的连续存储空间。
•适用于频繁的插入和删除操作:由于链表的特点,插入和删除操作的时间复杂度为O(1),效率较高。
然而,单链表的访问和搜索操作的效率较低,需要从头节点开始遍历整个链表。
此外,由于每个节点需要额外的指针来存储下一个节点的地址,导致存储开销相对较高。
总的说来,单链表的存储结构使得它适用于需要频繁进行插入和删除操作而不关心随机访问的场景。
单链表数据结构

插入
if (p != NULL && j == i-1) { // 找到第i个结点
s = (LinkList) malloc ( sizeof (LNode)); // 生成新结点
s->data = e;
// 数据域赋值
s->next = p->next; //新结点指针指向后一结点
p->next = s; return OK;
6、销毁
4.6 销毁操作
while(L) { p = L->next; free(L); L=p;
// p指向第一结点(头节点为“哑结点”) // 释放首结点 // L指向p
}
// 销毁完成后,L为空(NULL)
算法的时间复杂度为:O(ListLength(L))
判空 求表长
4.7 其它操作
if(L->next==NULL) return TRUE; // 空
5、清空
4.5 清空操作
while (L->next) { p = L->next; L->next = p->next; free(p);
// p指向当前结点 // 头结点指向当前结点的后结点 // 释放当前结点内存
}
// 清空完成后,仍保留头结点L
算法的时间复杂度为:O(ListLength(L))
点。
5.1.2 逆序建立单链表
①建立一个带头结点的空单链表;
②输入数据元素ai,建立新结点p, 并把p插入在头结点之后成为第一个 结点。
③重复执行②步,直到完成单链表的 建立。
a1
a2 a1
创建出来的链表 点顺序与插入操作
顺序相反。
JAVA数据结构——单链表的操作

单链表的操作方法一:package ch02;(1)建立结点类Node.javapublic class Node {public Object data;//存放结点数据值public Node next;//存放后继结点//无参构造函数public Node(){ this(null,null);}//只有结点值的构造函数public Node(Object data){ this(data,null);}//带有节点值和后继结点的构造函数public Node(Object data,Node next){ this.data=data;this.next=next;}}(2)建立链表及操作LinkList.javapackage ch02;import java.util.Scanner;public class LinkList implements IList{public Node head;//单链表的头指针//构造函数初始化头结点public LinkList(){head=new Node();}//构造函数构造长度为n的单链表public LinkList(int n,boolean Order) throws Exception{ this();if(Order)create1(n); //头插法顺序建立单链表elsecreate2(n); //尾插法逆序建立单链表}//头插法顺序建立单链表public void create1(int n) throws Exception{Scanner sc=new Scanner(System.in);System.out.println("请输入结点的数据(头插法):”);for(int i=0;i<n;i++){insert(0,sc.next());}}//尾插法逆序建立单链表public void create2(int n) throws Exception{Scanner sc=new Scanner(System.in);System. out.println("请输入结点的数据(尾插法):");for(int i=0;i<n;i++){insert(length(),sc.next());}}//将链表置空public void clear(){head.data=null;head.next=null;}//判断链表是否为空public boolean isEmpty(){return head.next==null;}//返回链表长度public int length(){Node p=head.next;int length=0;while(p!=null){p=p.next;length++;//返回P不空长度length加1}return length;}//读取并返回第i个位置的数据元素public Object get(int i) throws Exception {Node p=head.next;int j;//从首结点开始向后查找,直到9指向第i个结点或者p为nullfor(j=0;j<i&&p!=null;j++){ p=p.next;}if(j>i||p==null)//i不合法时抛出异常throw new Exception("第"+i+”个数据元素不存在”);return p.data;}//插入乂作为第i个元素public void insert(int i, Object x) throws Exception{ Node p=head;int j=-1;//寻找第i个结点的前驱i-1while(p!=null&&j<i-1){p=p.next;j++;}if(j>i-l||p==null)//i不合法时抛出异常throw new Exception("插入位置不合法”);Node s=new Node(x);s.next=p.next;p.next=s;}//删除第i个元素public void remove(int i) throws Exception{ Node p=head;int j=-1;while(p!=null&&j<i-1){//寻找第i-1 个节点p=p.next;j++;}if(j>i-1||p.next==null)throw new Exception("删除位置不合法”);p.next=p.next.next;}//返回元素x首次出现的位序号public int indexOf(Object x) {Node p=head.next;int j=0;while(p!=null&&!p.data.equals(x)){p=p.next;j++;if(p!=null)return j;elsereturn -1;}public void display(){Node p=head.next;while(p!=null){if(p.next==null)System.out.print(p.data);elseSystem.out.print(p.data+"f );p=p.next;}}}(3)建立测试类Test.javappublic class test {public static void main(String[] args) throws Exception { // TODO Auto-generated method stubScanner sc=new Scanner(System.in);boolean or;int xz,xx;System.out.println("请选择插入的方法:0、头插法,1、尾插法");xz=sc.nextInt();if(xz!=0)or=true;elseor=false;System. out.println("请插入的结点的个数:”);xx=sc.nextInt();LinkList L=new LinkList(xx,or);System.out.println("建立的链表为:");L.display();System.out.println();System.out.println("链表的长度:"+L.length());System. out.println(”请输入查找的结点的数据:”);Object x=sc.next();int position=L.indexOf(x);System.out.println("结点的数据为:"+x+"的位置为:"+position); System. out.println("请输入删除的结点的位置:”);int sr=sc.nextInt();L.remove(sr);L.display();System.out.println();System.out.println("链表的长度:"+L.length()); }品P rob I em & J a vs d oc / Declaration Q Error Log 里Con sole-M、、■=:termin8ted> test [3] [Java Application] C U &ert\Ad im i n i st rat o r\Ap p Data\L o cs I请选择插入.的方法:0、头插法,lv星插法请插入的特点的个数:请愉入结点的颓据(尾插法):A B C E D F建立的旌表为;A+B T C+E T D+F链表的长度:6请输入查找的结点的数据:结点的数据为:E的位置为:3请输入删除的结点的位置,R+B T E+DW道表的长度:S方法二(引入get和set方法)Package sy;import java.util.Scanner;//单链表的结点类public class Node {private Object data; //存放结点值private Node next; //后继结点的引用public Node() { //无参数时的构造函数this(null, null);}public Node(Object data) { // 构造值为data 的结点this(data, null);}public Node(Object data, Node next) {//构造值为data 和next 的结点构造函数this.data = data;this.next = next;}public Object getData() { return data;}public void setData(Object data) {this.data = data;}public Node getNext() { return next;public void setNext(Node next) { this.next = next;}}//实现链表的基本操作类public class LinkList {Node head=new Node();//生成一个带头结点的空链表//根据输入的一系列整数,以0标志结束,用头插法建立单链表public void creat() throws Exception {Scanner sc = new Scanner(System.in); //构造用于输入的对象for (int x=sc.nextInt(); x!=0; x=sc.nextInt()) //输入若干个数据元素的值(以0结束) insert(0, x);//生成新结点,插入到表头}//返回带头结点的单链表中第i个结点的数据域的值。
数据结构课件单链表

删除链表中的节点需要遍历至指定位置,时间复杂度为 O(n)。
查找节点
在链表中查找一个节点需要遍历整个链表,时间复杂度为 O(n)。
空间复杂度
空间占用
单链表的空间占用主要取决于链表中的 节点数,因此空间复杂度为O(n)。
VS
内存分配
每个节点需要分配内存空间存储数据和指 针,因此内存分配的空间复杂度也为O(n) 。
需要根据数据元素顺 序进行遍历的场景, 如排序算法等。
需要频繁插入、删除 操作的场景,如动态 规划、图算法等。
02
单链表的实现
创建单链表
定义节点结构体
首先需要定义一个节点结构体,包含 数据域和指针域两个部分,数据域用 于存储数据,指针域用于指向下一个 节点。
初始化头节点
创建一个头节点,并将其指针域指向 NULL,表示单链表的起始位置。
05
单链表常见问题与解决方 案
循环链表
总结词
循环链表是一种特殊类型的单链表,其中尾节点的指针指向头节点,形成一个闭环。
详细描述
在循环链表中,由于尾节点的指针指向头节点,因此遍历链表时需要特别注意,以避免无限循环。常见的解决方 法是在遍历时记录已经访问过的节点,避免重复访问。
链表中的重复元素
总结词
链表中可能存在重复元素的问题,这会影响数据处理的正确性。
详细描述
为了解决这个问题,可以在插入节点时检查新元素是否已存在于链表中。如果存在,则不进行插入操 作。另外,也可以使用哈希表等数据结构来快速查找重复元素。
链表的排序
总结词
对链表进行排序是常见的需求,但链表的排 序算法通常比数组的排序算法复杂。
合并单链表
总结词
将两个已排序的单链表合并为一个新的已排序的单链表。
单链表基本操作

单链表基本操作在计算机科学里,链表是一种常见的数据结构,它可以用来解决各种复杂的问题。
其中,单链表是最常见的一种,它由一系列节点组成,每个节点包含了一个数据元素和一个指针,指向下一个节点。
这篇文章将介绍单链表的基本操作,包括创建、插入、删除和遍历等。
创建单链表创建单链表是基本操作之一,它有两种方法:头插法和尾插法。
头插法是从链表的头节点开始,逐个将新节点插入。
具体来说,创建一个空链表,设置一个头节点,将头节点的指针指向空;依次输入新节点,将新节点的指针指向表头,将表头的指针指向新节点。
这样,每插入一个新节点就成为了新的表头,即最后插入的节点为新的表头。
尾插法则是从链表的尾节点开始,逐个将新节点插入。
具体来说,创建一个空链表,设置一个头节点,将头节点的指针指向空;依次输入新节点,将新节点的指针指向空,将最后一个节点的指针指向新节点。
这样,最后插入的节点为尾节点,它的指针值为空。
插入节点插入节点是指在单链表的任意位置插入一个新节点。
插入节点的前提是找到插入位置,可以通过遍历单链表来查找插入位置。
插入新节点的基本步骤如下:1、创建新节点;2、将新节点的指针指向待插入节点的后继节点;3、将待插入节点的指针指向新节点。
删除节点删除节点是指删除单链表中的任意节点。
删除节点的前提是找到删除的节点位置,可以通过遍历单链表来查找删除位置。
删除节点的基本步骤如下:1、找到要删除的节点;2、将该节点的前驱节点的指针指向该节点的后继节点;3、删除该节点。
遍历节点遍历节点是指按照链表的顺序依次访问链表中的各个节点。
遍历节点的基本步骤如下:1、从链表的头节点开始遍历;2、依次访问每个节点的数据元素;3、通过指针访问下一个节点,直到遇到尾节点。
优缺点单链表的优点是简单,灵活,易于实现和扩展,可以方便地进行插入和删除等操作。
其缺点是存在指针开销,查找元素时需要遍历整个链表,不能直接访问链表中任意位置的节点。
总结单链表是一种最常用的数据结构,它是由一系列节点组成,每个节点包含一个数据元素和一个指针,指向下一个节点。
数据结构-链表

链表一种数据结构的链接实现是指按链式存储方式构建其存储结构,并在此链式存储结构上实现其基本运算。
线性表的常见链式存储结构有单链表、循环链表和双链表,其中最简单的单链表。
本节讨论单链表的组织方法以及线性表的基本运算在单链表上的实现。
单链表示法的基本思想是用指针表示结点间的逻辑关系。
因此单链表的一个存储结点包含两个部分,结点形式如下:其中,data部分称为数据域,用于存储线性表的一个数据元素。
next部分称为指针域或链域,用于存放一个指针,该指针指向本结点所含数据元素的直接后继所在的结点。
从上述单链表中可以联想到我们生活中的火车,还有一种火车只有火车头。
假设数据元素的类型为Datatype。
单链表的类型定义如下:typedef struct node{Datatype data;struct node * next;} node,* LinkList;struct node表示链表的结点,一个结点是由两个域数据域data和指针域next组成的记录(每个域实际上相当于一个变量),而next本身又是一个pointer类型的指针型变量。
这个定义与上面给出的单链表的结点形式一致。
单链表的简单操作:1、初始化建立一个空表。
空表由一个头指针和一个头结点(该结点同时也是尾结点)组成。
LinkList Initiate_LinkList()/* 建立一空表 */{ LinkLis head;head= malloc(sizeof(node));head -> next = NULL;return head;}2、定位:按值查找。
按从前往后的顺序,依次比较单链表中各表结点数据域的值与给定值X,第一个值与X相等的表结点的序号就是结果。
若没有这样的结点,运算结果为0。
int Locate_LinkList(LinkList head,Datatype x){ Node *p;p = head; /* 置初值 */p=p->next;j = 0; /* 置初值 */while((p!= NULL)&&(p -> data != x)){ p = p -> next;j ++;} /* 未达尾结点又未找到等于x的结点时继续扫描 */if (p -> data == x)return(j+1);elsereturn(0);}3、插入:把新的结点x插入到i结点之前。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
数据结构的概念:数据的逻辑结构+ 数据的存储结构+ 数据的操作;数据的数值:=====》数据===》数值型数据整形浮点数ASCII非数值型数据图片声音视频字符=====》数据元素=====》基本项组成(字段,域,属性)的记录。
数据的结构:逻辑结构----》线性结构(线性表,栈,队列)----》顺序结构----》链式结构----》非线性结构(树,二叉树,图)----》顺序结构----》链式结构存储结构-----》顺序存储-----》链式存储-----》索引存储-----》哈希存储==散列存储数据的操作:增删改查DS ====》数据结构===》DS = (D,R);数据结构中算法:1、定义:有穷规则的有序集合。
2、特性:有穷性确定性输入输出3、算法效率的衡量时间复杂度计算===》算法中可执行依据的频度之和,记为:T(n)。
是时间的一种估计值不是准确值。
计算结果的分析:1 将最终结果的多项式中常数项去掉2 只保留所有多项式中最高阶的项3 最后的最高阶项要去掉其常数项时间复杂度的量级关系:常量阶====》对数阶===》线性阶===》线性对数阶====》平方阶===》立方阶===》指数阶以上关系可以根据曲线图来判断算法对时间复杂度的要求空间复杂度计算====》算法执行过程中所占用的存储空间的量级,记为:D(n)。
计算方法是在运行过程中申请的动态内存的量级计算。
/////////////////////////////////////////////////////////////////////////////////////////////////线性表顺序存储====》顺序表(数组)链式存储====》单链表特征:对于非空表,a0是表头没有前驱。
an-1 是表尾没有后继ai的每个元素都有一个直接前驱和直接后继基本操作:创建表=====》增加元素====》删除元素====》改变元素值====》查询元素1、顺序表的操作1.1 创建顺序表=====》定义个指定类型的数组====》int a[100] ={0};#define N 10typedef int datatype;typedef struct{datatype data[N]; ///表的存储空间int last; ///表尾下标,表示当前顺序表的最后存储的位置}sqlist,*sqlink; /// sqlist 表结构类型sqlink 表结构指针sqlink = sqlist *sqlist sq; ////栈区sqlink psq = (sqlink)malloc(sizeof(sqlist));///堆区1.2 增加顺序表元素操作(从头开始增加,插入)////从头增加sq.data[st] = values;st++;///插入void insert(L, x,i);====>L 就是顺序表,x 要插入的数据= values, i是要插入的位置{///防边界处理for(j=st;j>i;j--){sq.data[j] = sq.data[j-1];}sq.data[i] = x;st++;}1.3 删除顺序表操作(从尾部删除,从中间位置删除)void delete(L,i) ====>L 就是要删除的顺序表,i 要删除的位置{///防边界处理for(j=i;j<st;j++){sq.data[j] = sq.data[j+1];}st--;}1.4 改变顺序表中的值void change(L,x,i) ////i 是数组元素的下标{sq.data[i] = x;}void change_vlue(L ,x1,x2) ////根据元素的值修改{for(j=0;j<st;j++){if(sq.data[j] == x1)sq.data[j] = x2;}}1.5 查询顺序表中的值void select(L,i){printf("%d \n",sq.data[i]);}1.6 判断表示空,还是满。
练习:根据以上提示,尝试编写简单的顺表常规操作,1、自动输入若干个数据并存储到顺序表中。
2、简单删除指定的表中数据3、修改指定的表中数据4、查询指定下标的数据值特点:1、顺序表的存储方便,遍历数据方便。
2、插入和删除效率较低。
3、每次要明确的连续地址空间,且一旦定义就不能修改。
2、单链表的操作链表本身有自己的结构,所有的链表成员都是结点。
每个结点应该至少有两个域:数据域+ 指针域基本结构:typedef int datatype;typedef stuct _node{datatype data;struct _node *next;}linknode,*linklist;基本操作:创建单链表====》linklist list = (linklist)malloc(sizeof(linknode));===>头结点list->data = 0;list->next = NULL;创建结点====》linknode * create_node(datatype value){linknode *newnode = (linknode *)malloc(sizeof(linknode));newnode->data = value;newnode->next = NULL;return newnode;}链表的插入(增加)1、头插入法===》每次新创建的结点总是头结点的下一跳int insert_head(linklist L ,linknode * pnode){linklist tmp = L;pnode->next = tmp->next;tmp->next = pnode;tmp->data ++;}2、尾插入法===》每次新创建的结点都是最后一个结点int insert_tail(linklist L ,linknode * pnode){linklist tmp = L;while(tmp->next){tmp= tmp->next;}tmp->next = pnode;tmp->data ++;}显示链表中所有节点数据:void show_linklist(linklist L){linklist tmp = L;while(tmp->next){tmp= tmp->next;printf("%d \n",tmp->data);}}练习:自动创建单链表并依次新建10个子节点分别用头插入法和尾插入法的方法将节点增加到链表中,最后用show_linklist函数遍历单链表并显示每个结点的数据域的值。
链表的删除int delete_link(linklist L ,datatype value){linklist tmp = L;linklist tmp2 = L->next;int flag = 0;while(tmp2){if(tmp2->data == value){tmp->next = tmp2->next;free(tmp2);flag = 1;}else{tmp = tmp->next;tmp2 = tmp2->next;}}if(flag)return 0;elsereturn -1;}链表的改值int delete_link(linklist L ,datatype value1,datatype value2){linklist tmp2 = L->next;while(tmp2){if(tmp2->data == value1){tmp2->data = value2;}else{tmp2 = tmp2->next;}}}链表的查询1、查询总个数=====>pritnf("%d",L->data);2、根据数据值查询对应的地址void Locate(linklist L ,datatype value)===>返回值是地址链表资源释放void free_linklist(linklist L){linklist tmp =NULL;while(L){tmp = L;L= L->next;free(tmp);}}特点:1、插入和删除效率高2、遍历效率低3、需要动态申请内存,可能存在内存泄露。
作业:提示用户任意输入10个整形数字,用链表方式存储。
输入完毕后可以任意删除其中三个数字,并将每次删除后的链表数据打印输出。