链表和模拟链表[插入数字]
来源:互联网 发布:java io分类 编辑:程序博客网 时间:2024/06/03 20:32
有一串已经从小到大排好序的数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; }
- 链表和模拟链表[插入数字]
- UVA11988(破损键盘) 使用数组模拟链表插入
- 链表的建立、插入和删除
- 数据结构 链表的查找和插入
- 链表的建立、插入和删除
- 双向链表建立、插入和删除
- 链表的删除和插入
- 链表的插入和删除
- 链表的插入和删除
- 链表排序:冒泡和插入
- 链表的插入和删除
- 链表的创建和插入
- 头插法和尾插法插入链表
- 链表的删除和插入
- 双向链表的插入和删除
- 为什么这段代码打印出来的不是数字,而是地址,链表插入的?
- 数字矩阵和模拟矩阵
- 模拟电子技术和数字电子技术
- 香农
- Android Handler leak 分析及解决办法
- MySQL TPS 和 QPS 的统计和IOPS
- C++ this指针的用法
- Linux子系统
- 链表和模拟链表[插入数字]
- Git 教程
- online_judge_1471
- 定制accept方法
- UVA 10891
- C语言及程序设计初步例程-8 数值数据类型及表示
- 树莓派-上手体验2
- Web网络流量检测软件NetWorx 5.1.3
- commons logging和log4j 通用配置