链表和模拟链表[插入数字]

有一串已经从小到大排好序的数2 3 5 8 9 10 18 26 32。现需要往这串数中插入6使其得到的新序列仍符合从小到大排列。如我们使用数组来实现这一操作,则需要将8和8后面的数都依次往后挪一位,如下

这样操作显然很耽误时间,如果使用链表则会快很多。

此时如果需要在8前面插入一个6,就只需像下图这样更改一下就可以了,而无需再将8及后面的数都依次往后挪一位。是不是很节省时间呢?

那么如何实现链表呢?在C语言中可以使用指针和动态分配内存函数malloc来实现。

指针大家都很熟悉了,下面说下动态存储方法

malloc(4);

malloc函数的作用就是从内存中申请分配指定字节大小的内存空间。上面这行代码就申请了4个字节。如果你不知道int类型是4个字节的,还可以使用sizeof(int)获取int类型所占用的字节数,如下:

malloc(sizeof(int));

现在你已经成功地从内存中申请了4个字节的空间来准备存放一个整数,可是如何来对这个空间进行操作呢?这里我们就需要用一个指针来指向这个空间,即存储这个空间的首地址

int *p;
p=(int *)malloc(sizeof(int));

需要注意,malloc函数的返回类型是void * 类型。void * 表示未确定类型的指针。在C和C++中,void * 类型可以强制转换为任何其他类型的指针。上面代码中我们将其强制转化为整型指针,以便告诉计算机这里的4个字节作为一个整体用来存放整数。为什么要分不同类型的指针呢?因为指针变量存储的是一个内存空间的首地址(第一个字节的地址),但是这个空间一共占用了多少个字节,用来存储什么类型的数,则是由指针的类型来标明的。这样系统才知道应该取多少个连续内存作为一个数据。

#include <stdio.h>
#include <stdlib.h> 

//这里创建一个结构体用来表示链表的结点类型
struct node
{
	int data;
	struct node *next;
};

int main()
{
	struct node *head,*p,*q,*t;
	int i,n,a;
	scanf("%d",&n);
	head = NULL;//头指针初始为空
	for(i=1;i<=n;i++)//循环读入n个数
	{
		scanf("%d",&a);
		//动态申请一个空间,用来存放一个结点,并用临时指针p指向这个结点
		p=(struct node *)malloc(sizeof(struct node));
		p->data=a;//将数据存储到当前结点的data域中
		p->next=NULL;//设置当前结点的后继指针指向空,也就是当前结点的下一个结点为空

		if(head==NULL)
			head=p;//如果这是第一个创建的结点,则将头指针指向这个结点
		else
			q->next=p;//如果不是第一个创建的结点,则将上一个结点的后继指针指向当前结点 

		q=p;//指针q也指向当前结点
	} 

	scanf("%d",&a);//读入待插入的数
	t=head;//从链表头部开始遍历
	while(t!=NULL)//当没有到达链表尾部的时候循环
	{
		if(t->next->data > a)//如果当前结点下一个结点的值大于待插入数,将数插入到中间
		{
			p=(struct node *)malloc(sizeof(struct node));//动态申请一个空间,用来存放新增结点
			p->data=a;
			p->next=t->next;//新增结点的后继指针指向当前结点的后继指针所指向的结点
			t->next=p;//当前结点的后继指针指向新增结点
			break;//插入完毕退出循环
		}
		t=t->next;//继续下一个结点
	} 

	//输出链表中的所有数
	t=head;
	while(t!=NULL)
	{
		printf("%d ",t->data);
		t=t->next;//继续下一个结点
	} 

	return 0;
}

如果你压根就很讨厌指针这些东西,没关系!链表还有另外一种使用数组来实现的方式,叫做模拟链表。链表中的每一个结点只有两个部分。我们可以用一个数组data来存储每序列中的每一个数。那每一个数右边的数是谁,这一点该怎么解决呢?这里我们只需再用一个数组right来存放序列中每一个数右边的数是谁就可以了。

上图的两个数组中,第一个整型数组data是用来存放序列中具体数字的,另外一个整型数组right是用来存放当前序列中每一个元素右边的元素在数组data中位置的。例如right[1]的值为2,就表示当前序列中1号元素右边的元素存放在data[2]中;如果是0,例如right[9]的值为0,就表示当前序列中9号元素的右边没有元素。现在需要在8前面插入一个6,只需将6直接存放在数组data的末尾即data[10]=6。接下来只需要将right[3]改为10,表示新序列中3号元素右边的元素存放在data[10]中。再将right[10]改为4,表示新序列中10号元素右边的元素存放在data[4]中。这样我们通过right数组就可以从头到尾遍历整个序列了(序列的每个元素的值存放在对应的数组data中),如下。

#include <stdio.h>
int main()
{
	int data[101],right[101]; 

	int i,n,t,len;
	//读入已有的数
	scanf("%d",&n);
	for(i=1;i<=n;i++)
		scanf("%d",&data[i]);
	len=n; 

	//初始化数组right
	for(i=1;i<=n;i++)
	{
		if(i!=n)
			right[i]=i+1;
		else
			right[i]=0;
	} 

	//直接在数组data的末尾增加一个数
	len++;
	scanf("%d",&data[len]); 

	//从链表的头部开始遍历
	t=1;
	while(t!=0)
	{
		if(data[right[t]]>data[len])//如果当前结点下一个结点的值大于待插入数,将数插入到中间
		{
			right[len]=right[t];//新插入数的下一个结点标号等于当前结点的下一个结点编号
			right[t]=len;//当前结点的下一个结点编号就是新插入数的编号
			break;//插入完成跳出循环
		}
		t=right[t];
	} 

	//输出链表中所有的数
	t=1;
	while(t!=0)
	{
		printf("%d ",data[t]);
		t=right[t];
	} 

	return 0;
}

时间: 2024-08-30 05:08:35

链表和模拟链表[插入数字]的相关文章

天梯 - 重排链表(模拟链表操作)

给定一个单链表 L?1??→L?2??→?→L?n−1??→L?n??,请编写程序将链表重新排列为 L?n??→L?1??→L?n−1??→L?2??→?.例如:给定L为1→2→3→4→5→6,则输出应该为6→1→5→2→4→3. 输入格式: 每个输入包含1个测试用例.每个测试用例第1行给出第1个结点的地址和结点总个数,即正整数N (≤105).结点的地址是5位非负整数,NULL地址用−表示. 接下来有N行,每行格式为: Address Data Next 其中Address是结点地址:Data

UVA11988 Broken Keyboard (a.k.a. Beiju Text)【数组模拟链表】

Broken Keyboard (a.k.a. Beiju Text) You're typing a long text with a broken keyboard. Well it's not so badly broken. The only problem with the keyboard is that sometimes the "home" key or the "end" key gets automatically pressed (inter

【NOIP 模拟赛】钟 模拟+链表

biubiu~~ 这道题实际上就是优化模拟,就是找到最先死的让他死掉,运用时间上的加速,题解上说,要用堆优化,也就是这个意思. 对于链表,单项链表和循环链表都不常用,最常用的是双向链表,删除和插入比较方便. 所谓挂链就是把链表中的值域换成一坨别的东东西...... #include <cstdio> inline void read(int &sum){ register char ch=getchar();bool symbol=0; for(sum=0;ch<'0'||ch&

UVA11988:悲剧文本(模拟链表)

You're typing a long text with a broken keyboard. Well it's not so badly broken. The only problem with the keyboard is that sometimes the "home" key or the "end" key gets automatically pressed (internally). You're not aware of this iss

B - Broken Keyboard (a.k.a. Beiju Text) 数组模拟链表

You're typing a long text with a broken keyboard. Well it's not so badly broken. The only problem with the keyboard is that sometimes the "home" key or the "end" key gets automatically pressed (internally). You're not aware of this iss

链表(三)——链表删除冗余结点&amp;插入结点到有序链表

1.一个以递增方式排列的链表,去掉链表中的冗余值. 思路一:设有两个指针p和q,使p不动,q依次往后循环直到p->data不等于q->data,再将中间的冗余数据删除. 思路二:设有两个指针p和q,使p在前,q在后,只要找到一个冗余就删除一个,依次往后删除. 输入的链表:1 3 3 3 3 6 6 8 9 10 删除后的链表:1 3 6 8 9 10 比较两种思路,思路二的想法相比于思路一要好,所以这里实现思路二的代码. 2.将一个结点插入到一个有序的链表中. 思路:首先要判定这个链表是递增排

C语言实现简单的单向链表(创建、插入、删除)及等效STL实现代码

实现个算法,懒得手写链表,于是用C++的forward_list,没有next()方法感觉很不好使,比如一个对单向链表的最简单功能要求: input: 1 2 5 3 4 output: 1->2->5->3->4 相当于仅仅实现了插入.遍历2个功能(当然遍历功能稍微修改就是销毁链表了) 用纯C写了份测试代码 /* 基本数据结构的定义以及函数的声明 */ typedef int ElemType; typedef struct Node { ElemType elem; struc

hdu5009 Paint Pearls (DP+模拟链表)

http://acm.hdu.edu.cn/showproblem.php?pid=5009 2014网络赛 西安 比较难的题 Paint Pearls Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1951    Accepted Submission(s): 631 Problem Description Lee has a str

地震预测(模拟链表)

A - 地震预测 FZU - 1492 怀特先生是一名研究地震的科学家,最近他发现如果知道某一段时间内的地壳震动能量采样的最小波动值之和,可以有效地预测大地震的发生. 假设已知一段时间的n次地壳震动能量的采样值为a1,a2,…an,那么第i 次采样的最小波动值为min{|ai-aj| | i<j<=n},即第i 次采样的最小波动值是其后n-i次采样值与第i次采样值之差的绝对值中最小的值,特别地,第n次采样的最小波动值为an. 请编写一个程序计算这n次采样的最小波动值之和. Input 本题有多