草庐IT

单链表的创建,插入,删除以及查找

Lookdrama 2023-04-13 原文

本文章依据学校的实验作业完成

目录

前言

一、链表是什么?

1.概念

2.链表的分类

二、单链表的创建,插入,删除以及查找

1.单链表的存储结构

2.单链表的创建

3.单链表的插入

4.单链表的删除

5.单链表的查找

6.主函数

7.完整代码

8.编译结果

三、总结



前言

链表是一种物理存储单元上非连续、非顺序的存储结构,由一系列结点组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。

一、链表是什么?

1.概念

链表是一种物理存储结构上非连续存储结构,数据元素的逻辑顺序是通过链表中的引用链接次序实现的。

逻辑上连续是我们想象的连续,并不是真正的连续。

2.链表的分类

单向双向,带头结点不带头结点,循环非循环,组合起来共有8种

二、单链表的创建,插入,删除以及查找

1.单链表的存储结构

typedef int ElemType;	//便于后期的修改 
 
//定义结点类型 
typedef struct Node {
    ElemType data;              //单链表中的数据域 
    struct Node *next;          //单链表的指针域 
}Node,*LinkedList;

2.单链表的创建

	//单链表的建立(头插法)
	
	LinkedList ListCreatH() {
	    Node *L;
	    L = (Node *)malloc(sizeof(Node));   //申请头结点空间
	    L->next = NULL;                      //初始化一个空链表
	    int i=0;
	    ElemType x;                         //x为链表数据域中的数据
	    while(i<10) {
	        Node *p;
	        p = (Node *)malloc(sizeof(Node));   //申请新的结点 
	        scanf("%d",&x);
	        p->data = x;                     //结点数据域赋值 
	        p->next = L->next;                    //将结点插入到表头L-->|2|-->|1|-->NULL 
	        L->next = p; 
	        i++;
	    }
	    return L; 
	} 
	 
	 
	//单链表的建立(尾插法)(注:比较常用)
	 
	LinkedList ListCreatT() {
	    Node *L;
		    L = (Node *)malloc(sizeof(Node));   //申请头结点空间
		    L->next = NULL;                  //初始化一个空链表
		    Node *r;
		    r = L;                          //r始终指向终端结点,开始时指向头结点 
			int i=0   ;                   //x为链表数据域中的数据
		    for(i=0;i<10;i++)
			{ 		
				Node *p;
		        p = (Node *)malloc(sizeof(Node));   //申请新的结点 
		        scanf("%d",&p->data);
		        r->next = p;                 //将结点插入到表头L-->|1|-->|2|-->NULL 
		        r = p; 						//将r结点移动到最后一个节点
		    }
		    r->next = NULL;  				//让r结点的指针域置空(链表创建完成)
		    return L; 
	}

3.单链表的插入

//单链表的插入,在链表的第i个位置插入x的元素
/*初始条件:单链表L已存在,1<=i<=ListLength(L)*/
/*在L中第i个位置之前插入新的数据元素e,L的长度加1*/
LinkedList ListInsert(LinkedList L,int i,ElemType x) {
    LinkedList pre;                      //pre为前驱结点 
    pre = L;
    int tempi = 0;
    for (tempi = 1; tempi < i; tempi++) {
    	pre = pre->next;                 //查找第i个位置的前驱结点 
	}
    Node *p;                                //插入的结点为p
    p = (Node *)malloc(sizeof(Node));
    p->data = x;             //主要代码
    p->next = pre->next;          //主要代码
    pre->next = p;
    return L;                           
} 

4.单链表的删除

//单链表的删除,在链表中删除第i个数据元素
/*初始条件:单链表L已存在,1<=i<=ListLength(L)*/
/*操作结果:删除L的第i个数据元素,L的长度减1*/ 
LinkedList ListDelete(LinkedList L,int i)
{
    LinkedList p,q;                   
	int j=2; 
    p = L->next;
    while(p->next&&j<i) {              //查找第i个位置 
        p=p->next;
		++j;
    }
    if(!(p->next)||j>i)			//第i个元素不存在
		printf("第i个元素不存在\n");
    q=p->next;				
	p->next=q->next;			//将q的后继赋值给p的后继 
    free(q);                    //释放q结点
    return L;
} 

5.单链表的查找

//单链表的查找
/*初始条件:单链表L已存在,1<=i<=ListLength(L)*/
/*操作结果:用e打印中第i个数据元素的值*/ 
 void GetElem(LinkedList L)
 {
 	int i,j=1;		//j为计数器 
 	int *e;
 	LinkedList p;		//声明一结点p 
 	printf("请输入查找的位置:");
 	scanf("%d",&i);
 	p=L->next;		//让p指向链表L的第一个结点 
 	while(p&&j<i)        //p不为空且到达i结点
 	{
 		p=p->next;		//让p指向下一个结点 
 		++j;	
 	}
 	if(!p||j>i)        //链表p为空否则链表长度过短
 		printf("第i个元素不存在");		//第i个元素不存在 
 	*e=p->data;				//取第i个元素的数据 
 	printf("%d\n",*e);
 }

6.主函数

int main() {
    LinkedList list,start;
 	printf("请输入单链表的数据:\n"); 
    list = ListCreatT();
    printf("成功创建链表:\n");
    for(start = list->next; start != NULL; start = start->next) {
    	printf("%d ",start->data);
	}
    printf("\n");
    menu();
    int i,option;
    ElemType x;
    do{
		printf("请输入选项:");
		scanf("%d",&option);
		switch(option)
		{
		   	case 1:
			{
			   	printf("请输入插入数据的位置:");
				scanf("%d",&i);
				printf("请输入插入数据的值:");
				scanf("%d",&x);
				ListInsert(list,i,x);
				printf("插入后的链表为:");
				//打印链表 
				for(start = list->next; start != NULL; start = start->next)
				{
					printf("%d ",start->data);
				}
				printf("\n");
					  break;
				}
			case 2:
			{
				int i; 
				printf("请输入删除的位置\n");
				scanf("%d",&i);
				ListDelete(list,i);
				printf("删除后的链表为:");
				//打印链表
				for(start = list->next; start != NULL; start = start->next)
				{
					printf("%d ",start->data);					
				}
				printf("\n");
				break;		
			}
			case 3:GetElem(list);			break;		
			case 0:break;	
			default:printf("输出错误!\n");break;
	   } 		
	}while(option>0);
    return 0;
}

7.完整代码

#include <stdio.h>
#include <stdlib.h>
 
typedef int ElemType;	//便于后期的修改 
 
//定义结点类型 
typedef struct Node {
    ElemType data;              //单链表中的数据域 
    struct Node *next;          //单链表的指针域 
}Node,*LinkedList;
 
 
 //建立菜单 
 void menu()
 {
  printf("*****1.单链表的插入*****\n");
  printf("*****2.单链表的删除*****\n");
  printf("*****3.单链表的查找*****\n");
  printf("*****0.     退出   *****\n");
 }
 
//单链表的初始化
 
LinkedList LinkListInit() {
    Node *L;
    L = (Node *)malloc(sizeof(Node));   //申请结点空间 
    if(L == NULL) 	//判断是否有足够的内存空间
	{  
        printf("申请内存空间失败\n");
    }
    L->next = NULL;                  //将next设置为NULL,初始长度为0的单链表 
 	return L;
}
 
 
	//单链表的建立(头插法)
	 
	 
	LinkedList ListCreatH() {
	    Node *L;
	    L = (Node *)malloc(sizeof(Node));   //申请头结点空间
	    L->next = NULL;                      //初始化一个空链表
	    int i=0;
	    ElemType x;                         //x为链表数据域中的数据
	    while(i<10) {
	        Node *p;
	        p = (Node *)malloc(sizeof(Node));   //申请新的结点 
	        scanf("%d",&x);
	        p->data = x;                     //结点数据域赋值 
	        p->next = L->next;                    //将结点插入到表头L-->|2|-->|1|-->NULL 
	        L->next = p; 
	        i++;
	    }
	    return L; 
	} 
	 
	 
	//单链表的建立(尾插法)
	 
	LinkedList ListCreatT() {
	    Node *L;
		    L = (Node *)malloc(sizeof(Node));   //申请头结点空间
		    L->next = NULL;                  //初始化一个空链表
		    Node *r;
		    r = L;                          //r始终指向终端结点,开始时指向头结点 
			int i=0   ;                   //x为链表数据域中的数据
		    for(i=0;i<10;i++)
			{ 		
				Node *p;
		        p = (Node *)malloc(sizeof(Node));   //申请新的结点 
		        scanf("%d",&p->data);
		        r->next = p;                 //将结点插入到表头L-->|1|-->|2|-->NULL 
		        r = p; 						//将r结点移动到最后一个节点
		    }
		    r->next = NULL;  				//让r结点的指针域置空 
		    return L; 
	}
 
 
//单链表的插入,在链表的第i个位置插入x的元素
/*初始条件:单链表L已存在,1<=i<=ListLength(L)*/
/*在L中第i个位置之前插入新的数据元素e,L的长度加1*/
LinkedList ListInsert(LinkedList L,int i,ElemType x) {
    LinkedList pre;                      //pre为前驱结点 
    pre = L;
    int tempi = 0;
    for (tempi = 1; tempi < i; tempi++) {
    	pre = pre->next;                 //查找第i个位置的前驱结点 
	}
    Node *p;                                //插入的结点为p
    p = (Node *)malloc(sizeof(Node));
    p->data = x; 
    p->next = pre->next;
    pre->next = p;
    return L;                           
} 
 
 
//单链表的删除,在链表中删除第i个数据元素
/*初始条件:单链表L已存在,1<=i<=ListLength(L)*/
/*操作结果:删除L的第i个数据元素,L的长度减1*/ 
LinkedList ListDelete(LinkedList L,int i)
{
    LinkedList p,q;                   
	int j=2; 
    p = L->next;
    while(p->next&&j<i) {              //查找第i个位置 
        p=p->next;
		++j;
    }
    if(!(p->next)||j>i)			//第i个元素不存在
		printf("第i个元素不存在\n");
    q=p->next;				
	p->next=q->next;			//将q的后继赋值给p的后继 
    free(q);
    return L;
} 
 
//单链表的查找
/*初始条件:单链表L已存在,1<=i<=ListLength(L)*/
/*操作结果:用e打印中第i个数据元素的值*/ 
 void GetElem(LinkedList L)
 {
 	int i,j=1;		//j为计数器 
 	int *e;
 	LinkedList p;		//声明一结点p 
 	printf("请输入查找的位置:");
 	scanf("%d",&i);
 	p=L->next;		//让p指向链表L的第一个结点 
 	while(p&&j<i)
 	{
 		p=p->next;		//让p指向下一个结点 
 		++j;	
 	}
 	if(!p||j>i)
 		printf("第i个元素不存在");		//第i个元素不存在 
 	*e=p->data;				//取第i个元素的数据 
 	printf("%d\n",*e);
 }
 
 
int main() {
    LinkedList list,start;
 	printf("请输入单链表的数据:\n"); 
    list = ListCreatT();
    printf("成功创建链表:\n");
    for(start = list->next; start != NULL; start = start->next) {
    	printf("%d ",start->data);
	}
    printf("\n");
    menu();
    int i,option;
    ElemType x;
    do{
		printf("请输入选项:");
		scanf("%d",&option);
		switch(option)
		{
		   	case 1:
			{
			   	printf("请输入插入数据的位置:");
				scanf("%d",&i);
				printf("请输入插入数据的值:");
				scanf("%d",&x);
				ListInsert(list,i,x);
				printf("插入后的链表为:");
				//打印链表 
				for(start = list->next; start != NULL; start = start->next)
				{
					printf("%d ",start->data);
				}
				printf("\n");
					  break;
				}
			case 2:
			{
				int i; 
				printf("请输入删除的位置\n");
				scanf("%d",&i);
				ListDelete(list,i);
				printf("删除后的链表为:");
				//打印链表
				for(start = list->next; start != NULL; start = start->next)
				{
					printf("%d ",start->data);					
				}
				printf("\n");
				break;		
			}
			case 3:GetElem(list);			break;		
			case 0:break;	
			default:printf("输出错误!\n");break;
	   } 		
	}while(option>0);
    return 0;
}

8.编译结果


三、总结

常考的知识点:链表的插入,删除的关键语句、在头部插入,中间插入,尾部插入的时间复杂度,以及单链表和顺序表的区别

在链表尾部添加(addLast())需要从头遍历,时间复杂度为O(n)
在链表头部添加(addFirst()),时间复杂度为O(1)
在链表任意位置添加(add(int index,E e)),平均情况下为O(n/2)=O(n)

单链表和顺序表的区别:

顺序表的优点:

  1. 元素可以随机存储
  2. 节省存储空间
  3. 元素位置可用一个简单、直观的公式表示并在常量时间内访问

                                                                顺序表的缺点:

  1. 在作插入或删除操作时,需要移动大量元素

单链表的优点:

  1. 链表是线性表的链式存储表示
  2. 链表中逻辑关系相邻的元素不一定在存储位置上相连,用一个链(指针)表示元素之间的邻接关系即:链表中结点的逻辑顺序和物理顺序不一定相同
  3. 在插入和删除时,不需要大量移动数据元素,只需找到结点,对该结点做删除和插入的工作即可

                                                                      单链表的缺点:

在访问第i个位置的元素时,需要遍历链表,不能想顺序表一样直接找到第i个位置。

有关单链表的创建,插入,删除以及查找的更多相关文章

  1. ruby - 如何在 Ruby 中顺序创建 PI - 2

    出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits

  2. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  3. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  4. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  5. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

  6. ruby - 我可以使用 Ruby 从 CSV 中删除列吗? - 2

    查看Ruby的CSV库的文档,我非常确定这是可能且简单的。我只需要使用Ruby删除CSV文件的前三列,但我没有成功运行它。 最佳答案 csv_table=CSV.read(file_path_in,:headers=>true)csv_table.delete("header_name")csv_table.to_csv#=>ThenewCSVinstringformat检查CSV::Table文档:http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Table.html

  7. ruby-on-rails - 无法使用 Rails 3.2 创建插件? - 2

    我对最新版本的Rails有疑问。我创建了一个新应用程序(railsnewMyProject),但我没有脚本/生成,只有脚本/rails,当我输入ruby./script/railsgeneratepluginmy_plugin"Couldnotfindgeneratorplugin.".你知道如何生成插件模板吗?没有这个命令可以创建插件吗?PS:我正在使用Rails3.2.1和ruby​​1.8.7[universal-darwin11.0] 最佳答案 随着Rails3.2.0的发布,插件生成器已经被移除。查看变更日志here.现在

  8. ruby - 如何使用 RSpec::Core::RakeTask 创建 RSpec Rake 任务? - 2

    如何使用RSpec::Core::RakeTask初始化RSpecRake任务?require'rspec/core/rake_task'RSpec::Core::RakeTask.newdo|t|#whatdoIputinhere?endInitialize函数记录在http://rubydoc.info/github/rspec/rspec-core/RSpec/Core/RakeTask#initialize-instance_method没有很好的记录;它只是说:-(RakeTask)initialize(*args,&task_block)AnewinstanceofRake

  9. ruby - 我可以使用 aws-sdk-ruby 在 AWS S3 上使用事务性文件删除/上传吗? - 2

    我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的

  10. ruby - 为什么 SecureRandom.uuid 创建一个唯一的字符串? - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?

随机推荐