对线性表理解以及C语言实现链表的插入删除等操作。
2016-03-23 00:00
781 查看
摘要: 用任意的储存单元储存线性表的数据元素,为了表示元素ai与它的后继元素ai+1之间的逻辑关系,除了储存本身的信息之外还需要储存一个指示其后继的信息,这两部分的信息组成数据元素a1的储存映像,称为结点(node)。它包含两个域:储存直接后继储存位置的域称为指针域。指针域中储存的信息称为指针或连链。n个结点链结成一个链表称为线性表。
我们首先用一个结构体定义链表的储存结构,代码如下。
在链表L中第i个元素之前插入一个新的元素:我们需要找到第i-1个结点,然后修改其指向后继的指针。假设新插入的元素e,新生成的结点为s,我们可以分为三个个步骤:1.让e的后继指向i-1的后继(也就是指向i),2.让i-1的后继的指针指向s,3.然后讲新插入的元素值赋给新插入结点的数据域。这样便插入了一个新的元素。代码如下:
要想在链表L中删除第i个元素与插入元素的思路相同,找到第i-1个结点,然后修改其后继的指针。假设删除第i个结点,一个中间变量。1.我们首先找到第i-1个结点;2.q=p->next,p->next=q->next;这样i-1结点的后继指针便指向了i+1结点,我们可以然后删除q,便删除了第i个结点。代码如下:
取出链表L中第i个元素的值:因为单链表是一种顺序储存结构,因此如果想要找到第i个元素首先需要找到第i-1个元素,
基本操作为移动指针,比较j和i,指针p始终指向链表中的第j个元素。代码如下:
查询链表L中与e元素相同的第一次出现的位序:我们可以遍历整个链表,找到元素后返回位序,并停止遍历;代码如下:
逆序插入法生成一个链表:和插入思想相同,生成头结点函数写在了主函数(测试函数与)中,最后会有说明。代码如下:
输出链表所有的值:遍历链表所有元素并依次输出。代码如下:
测试链表的长度:代码如下:
接下来我们测试一下程序的运行结果,在测试程序中生成的链表元素个数为5,结点的个数(包含头结点)为6。1.输入的数据为11,12,13,14,15;2.逆序生成链表输出;3.在第四个元素之前插入“8”然后输出;4.删除第四个元素在输出;5.取出第二个元素的值;6.链表的长度;7.返回元素"11"的位序。代码如下:
运行结果如下:
总结:
优点:1.它是一种动态储存结构,整个储存空间供多链表共用;2.使用时不用预先分配空间;3.插入删除方便;
缺点:1.指针占用额外储存空间,;2.不能随机存取,查找速度慢;
-------------------------------------------------------------------------华丽分割线-----------------------------------------------------
学习数据结构链表后记录,有错误的欢迎指正。
我们首先用一个结构体定义链表的储存结构,代码如下。
#include<stdio.h> #include<stdlib.h> typedef int ElemType; /*-------------线性表的链式储存结构-----------------*/ typedef struct LNode{ ElemType data; struct LNode *next; }LNode,*LinkList; typedef int Status;
在链表L中第i个元素之前插入一个新的元素:我们需要找到第i-1个结点,然后修改其指向后继的指针。假设新插入的元素e,新生成的结点为s,我们可以分为三个个步骤:1.让e的后继指向i-1的后继(也就是指向i),2.让i-1的后继的指针指向s,3.然后讲新插入的元素值赋给新插入结点的数据域。这样便插入了一个新的元素。代码如下:
Status ListInsert_L(LinkList *L,int i,ElemType e)/*在L中第i个元素之前插入新的元素e*/ { LinkList p,s; int j=0; p=*L; while(p&&j<i-1) /*寻找第i-1个节点*/ { p=p->next; ++j; } if(!p||(j>i-1))return 0;/*i小于1或者大于表长加1*/ s=(LinkList)malloc(sizeof(LNode));/*生成新的节点*/ s->next=p->next;p->next=s;/*插入到L中*/ s->data=e; return 1; }
要想在链表L中删除第i个元素与插入元素的思路相同,找到第i-1个结点,然后修改其后继的指针。假设删除第i个结点,一个中间变量。1.我们首先找到第i-1个结点;2.q=p->next,p->next=q->next;这样i-1结点的后继指针便指向了i+1结点,我们可以然后删除q,便删除了第i个结点。代码如下:
Status ListDelete_L(LinkList *L,int i)/*删除L中第i个数据元素*/ { LinkList p,q; int j; p=*L;j=0; while(p->next&&j<i-1)/*寻找第i个结点,并令p指向其前驱*/ { p=p->next;++j; } if(!p->next||(j>i-1))return 0;/*删除位置不合理*/ q=p->next;p->next=q->next;/*删除并释放结点*/ free(q); return 1; }
取出链表L中第i个元素的值:因为单链表是一种顺序储存结构,因此如果想要找到第i个元素首先需要找到第i-1个元素,
基本操作为移动指针,比较j和i,指针p始终指向链表中的第j个元素。代码如下:
Status GetElem_L(LinkList L,int i,ElemType *e)/*取出链表L中第i个元素的值*/ { LinkList p;int j; p=L;j=0; while(p&&j<i) /*寻找第i个结点*/ { p=p->next;++j; } if(!p||j>i)return 0; *e=p->data; /*用来返回第i个结点的值*/ return 1; }
查询链表L中与e元素相同的第一次出现的位序:我们可以遍历整个链表,找到元素后返回位序,并停止遍历;代码如下:
Status LocateElem_L(LinkList *L,ElemType e,int *n/*,compare()*/)/*查询链表中与e相同元素的第一个值*/ { /*并用n返回其位置*/ LinkList p; int j=0; p=*L; while(p)/*判断p是否为空*/ { p=p->next;++j; if(p->data==e)/*判断p所指向的数据的值是否与e相等*/ { *n=j;return 1; break; } } return 0; }
逆序插入法生成一个链表:和插入思想相同,生成头结点函数写在了主函数(测试函数与)中,最后会有说明。代码如下:
void CreateList_L(LinkList *L,int n)/*逆序输入n个元素的值,n为链表元素的个数*/ { LinkList p,s; p=*L; for(n;n>0;--n) { int tmp; s=(LinkList)malloc(sizeof(LNode));/*生成新的结点*/ scanf("%d",&tmp); s->data=tmp; /*插入元素的值*/ s->next=p->next;p->next=s; /*插入到表头*/ } }
输出链表所有的值:遍历链表所有元素并依次输出。代码如下:
Status ListTraverse(LinkList *L)/*用于输出链表的所有值*/ { LinkList p; p=*L; p=p->next;/*让p指向第一个结点*/ while(p)/*判断p是否为空*/ { printf("%d\t",p->data);/*输出元素的值,并让p指向下一个结点*/ p=p->next; } printf("\n"); return 0; }
测试链表的长度:代码如下:
Status ListLenght_L(LinkList *L)/*用于测链表的长度*/ { int j=0; LinkList p=*L; while(p)/*判断p是否为空*/ { j++; p=p->next; } return j; }
接下来我们测试一下程序的运行结果,在测试程序中生成的链表元素个数为5,结点的个数(包含头结点)为6。1.输入的数据为11,12,13,14,15;2.逆序生成链表输出;3.在第四个元素之前插入“8”然后输出;4.删除第四个元素在输出;5.取出第二个元素的值;6.链表的长度;7.返回元素"11"的位序。代码如下:
void main()/*测试函数*/ { int n,n1,ex;/*用n表示取出元素的值,n1表示测试链表的长度,ex表示第一个与元素e相等的位置*/ LinkList L=(LinkList)malloc(sizeof(LNode)); L->next=NULL; printf("请输入5个元素,用来逆序生成链表:"); CreateList_L(&L,5);/*我们设置为5个元素*/ printf("生成的链表为:"); ListTraverse(&L); ListInsert_L(&L,4,8); printf("在第四个元素前面插入元素8:生成的链表为:"); ListTraverse(&L); ListDelete_L(&L,4);/*删除第四个结点*/ printf("删除第四个元素生成的链表为:"); ListTraverse(&L); GetElem_L(L,2,&n);/*取出第二个元素的值*/ printf("第二个元素的值为:%d\n",n); n1=ListLenght_L(&L);/*用来求链表的长度*/ printf("链表的长度为:%d\n",n1); if( LocateElem_L(&L,11,&ex))/*查找与元素11相同的位序*/ { printf("与元素11相同的元素的位序为:%d\n",ex); } else { printf("与元素11相同的元素的位序为:查找失败"); } system("pause"); }
运行结果如下:
总结:
优点:1.它是一种动态储存结构,整个储存空间供多链表共用;2.使用时不用预先分配空间;3.插入删除方便;
缺点:1.指针占用额外储存空间,;2.不能随机存取,查找速度慢;
-------------------------------------------------------------------------华丽分割线-----------------------------------------------------
学习数据结构链表后记录,有错误的欢迎指正。
相关文章推荐
- “百度与站长”更新:关于网站收录,删除,seo等
- 用vbs删除某些类型文件和磁盘空间报告的脚本
- QQ聊天记录删除了怎么恢复简单方法
- vbs删除注册表项的代码
- 迅速删除非法文件名的批处理代码
- 通过批处理实现删除运行、查找等处的历史记录的代码
- Shell中删除某些文件外所有文件的3个方法
- 删除文件提示文件正在被另一个人或程序使用的解决方法
- 关于.LDB文件 .ldb文件的产生 .ldb文件的删除方法
- asp 合并记录集并删除的sql语句
- SQL Server中数据行批量插入脚本的存储实现
- SQLserver 数据库危险存储过程删除与恢复方法
- sql自增长设置与删除的深入分析
- 使用 Iisext.vbs 删除 Web 服务扩展文件的方法
- linux oracle数据库删除操作指南
- jQuery删除一个元素后淡出效果展示删除过程的方法
- 使用 Iisftpdr.vbs 删除FTP虚拟目录(支持本地与远程)
- 必须会的SQL语句(四) 数据删除和更新
- mssql SA帐号的改名和删除
- Oracle中插入特殊字符:&和'的解决方法汇总