链表的基本功能实现
2015-12-12 19:48
716 查看
前言 : 链表的实现,查询,插入,删除,这些简单的操作。在平时的学习中,经常会遇见,故以单链表为例做个总结。链表的优缺点,以及适用情况在前面的一篇文中就提到过,就不作介绍了。
一、链表的定义
单链表存储结构
LinkList与LNode *同为结构体指针类型,这两种类型定义本质上是等价的,为提高程序的可读性,通常用LinkList定义头指针,LNode*定义指向单链表中任意结点的指针变量。例如,LinkList L,则L为单链表的头指针;使用LNode *p,则p为指向单链表中任意结点的指针,用*p代表该结点。
二、链表的基本操作的实现
1.初始化
[算法思想]
1)生成新的结点作为头结点,用头指针L指向头结点。
2)头结点的指针域置空。
[算法描述]
2.查找
2.1按序号查找
[算法思想]
从链表的第一个结点(L->next)开始顺着链域扫描,用指针p指向当前扫描到的结点,p的初值指向第一个结点(p=L->next)。用j做计数器,累计当前扫描过的结点数,j的初值为1,当p指向扫描的下一结点时,计数器j相应加1。当j=i时,p所指的结点就是要找的第i个结点。
[算法描述]
2.2按值查找
[算法思想]
链表中查找其值与给定值e相等的数据元素的过程和顺序表(数组)类似,从第一个结点起,依次和e相比较,如果找到一个其值与e相等的数据元素,则返回其在链表中的“位置”;如果查遍整个链表都没有找到其值和e相等的元素,则返回“NULL”。因此需要设置一个指针变量p顺链扫描,直到p为“NULL”,或者p->data和e相同为止。
[算法描述]
3.插入
[算法思想]
将值为e的新结点插入到表的第i个结点的位置上,即插入到结点a(i-1)与ai之间,分为以下几步:
1)找到结点a(i-1)并由指针p指向该结点。
2)生成一个新结点*s。
3)将新结点*s的数据域置为e。
4)将新结点*s的指针域指向结点ai;
5)令结点a(i-1)的指针域指向新结点*s。
[算法描述]
[算法思想]
要删除单链表的第i个结点ai,分以下几步:
1)找到结点a(i-1)并由指针p指向该结点。
2)临时保存待删除结点ai的结点在q中,以备释放。
3)令p->next指向ai的直接后继结点。
4)将待删除结点ai的值保留在e中(此步根据实际应用情况可以省略)。
5)释放结点ai的空间。
链表的创建方法可以分为前插法和后插法。因为后插入比较常用和清晰,故在这里只是实现了后插法。
[算法思想]
后插法是通过将新结点逐个插入到链表的尾部来创建链表。同前插法一样首先要建立一个只有头结点的空链表L。不同的是,为了使新结点能插入到表尾,需要增加一个尾指针r指向链表的尾结点。初始时,r同L均指向头结点。每读入一个数据元素则申请一个新结点,将新结点插入到尾结点*r之后,再使r指向新的尾结点。
[算法描述]
[完整代码]
[运行结果]
后语:链表的反转,双向链表,循环链表这些未实现的有机会再补上。
一、链表的定义
单链表存储结构
typedef struct LNode { int data; /*结点的数据域*/ struct LNode *next; /*结点的指针域*/ }LNode,*LinkList; /*LinkList为指向结构体LNode的指针类型*/
LinkList与LNode *同为结构体指针类型,这两种类型定义本质上是等价的,为提高程序的可读性,通常用LinkList定义头指针,LNode*定义指向单链表中任意结点的指针变量。例如,LinkList L,则L为单链表的头指针;使用LNode *p,则p为指向单链表中任意结点的指针,用*p代表该结点。
二、链表的基本操作的实现
1.初始化
[算法思想]
1)生成新的结点作为头结点,用头指针L指向头结点。
2)头结点的指针域置空。
[算法描述]
int InitList_L(LinkList &L) { L=new LNode; /*生成新结点作为头结点,用头指针L指向头结点*/ /*L->data=? 头指针的数据域可以不存储任何信息,也可以存储如线性表长度等类似的附加信息*/ L->next=NULL; /*头结点指针域置空*/ return OK; }
2.查找
2.1按序号查找
[算法思想]
从链表的第一个结点(L->next)开始顺着链域扫描,用指针p指向当前扫描到的结点,p的初值指向第一个结点(p=L->next)。用j做计数器,累计当前扫描过的结点数,j的初值为1,当p指向扫描的下一结点时,计数器j相应加1。当j=i时,p所指的结点就是要找的第i个结点。
[算法描述]
int GetElem_L(LinkList L,int i,int &e) { /*在带头结点的单链表L中查找第i个元素*/ LNode *p=new LNode; p=L->next; int j=1; /*初始化,p指向第一个结点,j为计数器*/ while(p && j<i) /*顺链域向后扫描,直到p指向第i个元素或p为空*/ { p=p->next; ++j; } if(!p || j>i) return ERROR; /*第i个元素不存在*/ e=p->data; return OK; }
2.2按值查找
[算法思想]
链表中查找其值与给定值e相等的数据元素的过程和顺序表(数组)类似,从第一个结点起,依次和e相比较,如果找到一个其值与e相等的数据元素,则返回其在链表中的“位置”;如果查遍整个链表都没有找到其值和e相等的元素,则返回“NULL”。因此需要设置一个指针变量p顺链扫描,直到p为“NULL”,或者p->data和e相同为止。
[算法描述]
int LocateElem_L(LinkList L,int e) { LNode *p=new LNode; p=L->next; int j=1; while( p&&p->data!=e) { p=p->next; j++; } if(!p)return NULL; /*查找失败返回NULL*/ return j; }
3.插入
[算法思想]
将值为e的新结点插入到表的第i个结点的位置上,即插入到结点a(i-1)与ai之间,分为以下几步:
1)找到结点a(i-1)并由指针p指向该结点。
2)生成一个新结点*s。
3)将新结点*s的数据域置为e。
4)将新结点*s的指针域指向结点ai;
5)令结点a(i-1)的指针域指向新结点*s。
[算法描述]
int ListInsert_L(LinkList &L, int i, int e) { /*在带头结点的单链表L中第i个位置之前插入元素e*/ LNode *p=new LNode; p=L; int j=0; while(p && j<i-1) /*找到第i-1个结点*/ { p=p->next; ++j; } if(!p || j>i-1) return ERROR; LNode *s=new LNode; s->data=e; /*将结点s的数据域置为e*/ s->next=p->next; /*将结点s插入L中*/ p->next=s; return OK; }4.删除
[算法思想]
要删除单链表的第i个结点ai,分以下几步:
1)找到结点a(i-1)并由指针p指向该结点。
2)临时保存待删除结点ai的结点在q中,以备释放。
3)令p->next指向ai的直接后继结点。
4)将待删除结点ai的值保留在e中(此步根据实际应用情况可以省略)。
5)释放结点ai的空间。
int ListDelete_L(LinkList &L,int i,int &e) { LNode *p=new LNode; p=L; int j=0; while(p->next && j<i-1) { p=p->next; ++j; } if(!p||j>i-1) return ERROR; LNode *q=p->next; /*临时保存被删结点的地址以备释放*/ p->next=q->next; /*改变删除结点前驱结点的指针域*/ e=q->data; delete q; /*释放删除结点的空间*/ return OK; }5.创建链表
链表的创建方法可以分为前插法和后插法。因为后插入比较常用和清晰,故在这里只是实现了后插法。
[算法思想]
后插法是通过将新结点逐个插入到链表的尾部来创建链表。同前插法一样首先要建立一个只有头结点的空链表L。不同的是,为了使新结点能插入到表尾,需要增加一个尾指针r指向链表的尾结点。初始时,r同L均指向头结点。每读入一个数据元素则申请一个新结点,将新结点插入到尾结点*r之后,再使r指向新的尾结点。
[算法描述]
void CreateList_L(LinkList &L,int n) { /*正位序输入n个元素的值,建立带表头结点的单链表L*/ LNode *r=new LNode; r=L; for(int i=0;i<n;i++) { LNode *p=new LNode; cin>>p->data; p->next=NULL; r->next=p; /*插入到表尾*/ r=p; /*r指向新的尾结点*/ } }
[完整代码]
#include<iostream> using namespace std; typedef struct LNode { int data; /*结点的数据域*/ struct LNode *next; /*结点的指针域*/ }LNode,*LinkList; const int OK=1; const int ERROR = -1; /*初始化*/ int InitList_L(LinkList &L,int n) { L=new LNode; /*生成新结点作为头结点,用头指针L指向头结点*/ /*L->data=? 头指针的数据域可以不存储任何信息,也可以存储如线性表长度等类似的附加信息*/ L->data=n; L->next=NULL; /*头结点指针域置空*/ cout<<endl<<"初始化成功...\n"<<endl; return OK; } /*按序号查找*/ int GetElem_L(LinkList L,int i,int &e) { /*在带头结点的单链表L中查找第i个元素*/ LNode *p=new LNode; p=L->next; int j=1; /*初始化,p指向第一个结点,j为计数器*/ while(p && j<i) /*顺链域向后扫描,直到p指向第i个元素或p为空*/ { p=p->next; ++j; } if(!p || j>i) /*第i个元素不存在*/ { cout<<"\n第"<<i<<"个元素不存在或表为空\n"<<endl; return ERROR; } e=p->data; cout<<"\n第"<<i<<"个元素为"<<e<<"\n"<<endl; return OK; } /*按值查找*/ int LocateElem_L(LinkList L,int e) { LNode *p=new LNode ; p=L->next; int j=1; while( p&&p->data!=e) { p=p->next; j++; } if(!p) { cout<<"\n元素"<<e<<"不存在或表为空\n"<<endl; return ERROR; } cout<<"\n元素"<<e<<"在链表的第"<<j<<"位\n"<<endl; return j; } /*插入*/ int ListInsert_L(LinkList &L, int i, int e) { /*在带头结点的单链表L中第i个位置之前插入元素e*/ LNode *p=L; int j=0; while(p && j<i-1) /*找到第i-1个结点*/ { p=p->next; ++j; } if(!p || j>i-1) { cout<<"\n第"<<i<<"元素不存在或表为空\n"<<endl; return ERROR; } LNode *s=new LNode; s->data=e; /*将结点s的数据域置为e*/ s->next=p->next; /*将结点s插入L中*/ p->next=s; cout<<"\n插入成功...\n\n"; return OK; } /*删除*/ int ListDelete_L(LinkList &L,int i,int &e) { LNode *p=L;int j=0; while(p->next && j<i-1) { p=p->next; ++j; } if(!p||j>i-1) { cout<<"\n第"<<i<<"元素不存在或表为空\n"<<endl; return ERROR; } LNode *q=p->next; /*临时保存被删结点的地址以备释放*/ p->next=q->next; /*改变删除结点前驱结点的指针域*/ e=q->data; delete q; /*释放删除结点的空间*/ cout<<"\n删除成功...\n\n"; return OK; } /*后插法创建*/ void CreateList_L(LinkList &L,int n) { /*正位序输入n个元素的值,建立带表头结点的单链表L*/ cout<<"依次输入"<<n<<"个元素:"; LNode *r=new LNode; r=L; for(int i=0;i<n;i++) { LNode *p=new LNode; cin>>p->data; p->next=NULL; r->next=p; /*插入到表尾*/ r=p; /*r指向新的尾结点*/ } cout<<"\n后插法创建链表成功...\n"<<endl; } int PrintList_L(LinkList L) { LNode *p=new LNode; p=L; p=p->next; if(p==NULL) { cout<<"\n链表为空!!!\n"<<endl; return ERROR; } cout<<"链表中的元素为:"; while(p) { cout<<p->data<<" "; p=p->next; } cout<<endl; return OK; } int main() { int n=0; cout<<"输入链表的长度:"; cin>>n; LinkList L; InitList_L(L,n); /*初始化*/ CreateList_L(L,n); /*创建链表*/ PrintList_L(L); int e=0; /*删除链表*/ ListDelete_L(L,1,e); PrintList_L(L); /*插入链表*/ ListInsert_L(L,1,e); PrintList_L(L); /*按值查找*/ LocateElem_L(L,2); /*按序号查找*/ GetElem_L(L,3,e); return 0; }
[运行结果]
后语:链表的反转,双向链表,循环链表这些未实现的有机会再补上。
相关文章推荐
- jwt(json-web-token)在rest中的实现--jersey
- linux内存泄漏检测
- APUE:实际用户ID和有效用户ID(euid)
- 推荐几篇学习rest风格的文章
- Mantle源代码阅读笔记 一
- (Fun)*((int*)*(int*)(&b)); http://bbs.csdn.net/topics/320008423
- 20151212jquery学习笔记--工具函数
- codeforces 418 C Square Table (随机算法)
- SAX解析XML文件
- VS2013下 开发简单的MFC小程序
- linux C 学习---函数指针
- JavaScript、CSS、HTML 实现用户注册页面与信息校验
- Tomcat 源码分析(转)
- 配置Caffe+VS2013+CUDA 6.5+Windows 8.1 64位系统
- 程序退出的实现方式
- 操作系统与网络实现 之十二
- Android 最火的快速开发框架XUtils
- 共享文件系统
- 基于rails的schedule网站开发(9):一些疑惑
- Java 开源博客 —— Solo 0.6.9 发布时间!