您的位置:首页 > 其它

链表的基本功能实现

2015-12-12 19:48 716 查看
前言 : 链表的实现,查询,插入,删除,这些简单的操作。在平时的学习中,经常会遇见,故以单链表为例做个总结。链表的优缺点,以及适用情况在前面的一篇文中就提到过,就不作介绍了。

一、链表的定义

单链表存储结构

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;
}


[运行结果]



后语:链表的反转,双向链表,循环链表这些未实现的有机会再补上。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: