首页 > 代码库 > 链表和模拟链表[插入数字]

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

有一串已经从小到大排好序的数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=http://www.mamicode.com/a;//将数据存储到当前结点的data域中>


如果你压根就很讨厌指针这些东西,没关系!链表还有另外一种使用数组来实现的方式,叫做模拟链表。链表中的每一个结点只有两个部分。我们可以用一个数组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; 
}


技术分享


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