链表的基本功能实现

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

一、链表的定义

单链表存储结构

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

[运行结果]


后语:链表的反转,双向链表,循环链表这些未实现的有机会再补上。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值