C/C++之单链表(含约瑟夫问题)经典总结

      在这个总结中,完成了大部分常用的单链表操作,如删除、插入结点,排序、逆序链表,约瑟夫问题等。约瑟夫问题的高效实现与分析参考其他经典算法,(从略)。

      实现源代码如下:

// LinkListUD.cpp : Defines the entry point for the console application.

//
//-----header files
#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <iostream.h>
#include <windows.h>
//-----type definition
typedef int ElemType;
//-----global variables in this files
//-----Linklist NODE
typedef struct LNode 
{
ElemType date;
struct LNode *next;
}linklist,*link;
//-------------------------统计链表长度:即结点个数-------------------
int Length(link pHead,BOOL bTypeofLinkList)
{   
if(pHead==NULL)
exit(0);
//----
link pCurr;
pCurr=pHead->next;
//----
int n=1;
if (bTypeofLinkList)    //单链表
{
while(pCurr->next!=NULL)
{
n++;
pCurr=pCurr->next;
}
//
n++;

else                    //单循环链表
{
while(pCurr!=pHead)
{
n++;
pCurr=pCurr->next;
}
}
return n;
}
//-----------------------------显示链表-------------------------//无空头结点
void DisplayList(link pHead,BOOL bTypeofLinkList)
{   
link p,hs;
p=pHead;
hs=pHead;
//---链表是否存在?
if(pHead==NULL)    //无空头结点
{
printf("List is empty or none\n");
exit(0);
}
//
if (bTypeofLinkList)  //单链表结点数据输出方法
{
while (p->next!=NULL)
{
cout<<p->date<<"->";
p=p->next;
}
//**********单链表做收尾工作
cout<<p->date<<endl; //此时p为尾结点   

else
{
//----------单循环链表结点数据输出方法
while(p->next!=hs)    //**********循环单链表判别条件:是否返回到头结点?
{
cout<<p->date<<"->";
p=p->next;
}
//**********单循环链表做收尾工作
cout<<p->date<<endl;    //p->next==hs,此时p为尾结点  
}
}
//---------------------------创建默认的单链表----------------------------//无空头结点
linklist *CreateDefaultList(BOOL bTypeofLinkList,int rec_length)
{
//------------
link pHead = (linklist*)malloc(sizeof(linklist));
if (pHead==NULL)
{
cout<<"默认链表创建失败!"<<endl;
return NULL;
}
link pCurr=NULL,pPrev=NULL;
//------------
int i=1;                //结点元素递增值:1,2,3,...,n。
pHead->date = i;
pPrev=pHead;
while (--rec_length>0)  //
{
pCurr = (linklist*)malloc(sizeof(linklist));
i++;
pCurr->date = i;
pPrev->next=pCurr;
pPrev = pCurr;
}
//单链表/单循环链表?---单链表-------------单循环链表
    (bTypeofLinkList)?(pCurr->next=NULL):(pCurr->next = pHead);
//pCurr->next = pHead;  //构成环状单链表(约瑟夫环),不带不存储数据的空头结点!
//
return pHead;
}
//---------------------------创建连续输入数据生成单链表----------------------------
linklist *CreateList(BOOL bTypeofLinkList)   //创建循环单链表
{
link pHead=NULL; //header node
link pCurr=NULL; //新增分配结点地址
link pPrev=NULL; //前结点地址
int iInput;
//create header node
pHead=(linklist *)malloc(sizeof(linklist));   //返回指针型地址值
pHead->next=NULL;
//----输入连续数据直到遇到-1时退出
cout<<"Please input node infomation on and on until -1"<<endl;
scanf("%d",&iInput);
pHead->date=iInput;
//把此头结点赋给尾结点
pPrev=pHead;
//
while(1)
{
//用户输入回车后,按用户指定的格式从键盘上把有效数据输入到指定的变量之中,残留的信息存在于stdin流(键盘缓冲区)。
//对同一次输入的残余信息多次scanf,则可以将有效字符串逐次扫描变量iInput中,即可以完成用户输入的含有空格、跳格的字段。
scanf("%d",&iInput);
//
if(iInput!=-1)   //将iInput值插入到新增结点上
{
//add new node
pCurr=(linklist *)malloc(sizeof(linklist));
//store ch
pCurr->date=iInput; 
//==============add node's linkship
pPrev->next=pCurr;
pPrev=pCurr;
//==============
//--temp->next is set to NULL
pCurr->next=NULL;
        }
else           
{   
if (bTypeofLinkList) //尾结点后继置空
{
pPrev->next=NULL; 

else                 //元素结束时才将其首尾相接,简明清晰
{
pPrev->next=pHead;       //end, tail point to header
}
break;
}
}
return pHead;
}
//-----------------------销毁链表--------------------------
char DestroyLinklist(link &L,BOOL bTypeofLinkList)
{
link p=L,judgeNode=L;
//------链表是否存在?
if (L==NULL)
{
printf("List is empty or none\n");
exit(0);
}
//--
if (bTypeofLinkList)      //单链表
{
while(L->next!=NULL)  //逐点销毁

p=L;
L=L->next;
free(p) ;         //删除节点用free
}
//--释放最后一个结点
p=L;
free(p);

else                           //单循环
{
while(L->next!=judgeNode)  //逐点销毁

p=L;
L=L->next;
free(p) ;
}
//--释放最后一个结点
p=L;
free(p);
}
//-----
L=NULL;  //
//
return 'y';
}
//-----------------------打印分隔栏------------------------
void PrintPolice()
{
cout<<"---------------------------------------------------------\n";
}
//-------------------------------------插入结点-------------------------------------
linklist *InsertNodeToList(link &L,int iSite,ElemType iNodeValue,BOOL bTypeofLinkList,int iLen)
{
link pPrev,pCurr,pHead;
int iStart;
pHead=L;
pPrev=L;        //某个前结点的地址
//----------插入头部
if (iSite==1)       //做为第一结点插入链表头部   
{
//Malloc向系统申请分配指定size个字节的内存空间。返回类型是 void* 类型。
//void* 表示未确定类型的指针。C,C++规定,void* 类型可以强制转换为任何其它类型的指针。
//pCurr= (link)malloc(sizeof(LNode));    //插入或者新增结点时才用malloc或者new
pCurr = new LNode;
pCurr->date=iNodeValue;
pCurr->next=NULL;
if (bTypeofLinkList)    //单链表
{
pCurr->next=pPrev;
//----pCurr作为头结点
pPrev=pCurr;
pHead=pCurr;
cout<<"结点已经插入"<<endl;

else                    //单循环
{
while (pPrev->next!=pHead)
{
pPrev=pPrev->next;
}
//
pPrev->next = pCurr;   
pCurr->next=pHead;    //最后结点后继指向第一结点
//----pCurr作为头结点
pHead=pCurr;
cout<<"结点已经插入"<<endl;
}
//
return pHead;
}
//--------------插入尾部
    if (iSite==(iLen+1))
    {
//pCurr= (link)malloc(sizeof(LNode));
pCurr = new LNode;
pCurr->date=iNodeValue;
pCurr->next=NULL;
if (bTypeofLinkList)   //单链表
{
while (pPrev->next!=NULL)
{
pPrev=pPrev->next;
}
//---
pPrev->next=pCurr;
cout<<"结点已经插入"<<endl;

else   //单循环
{
while (pPrev->next!=pHead)
{
pPrev=pPrev->next;
}
//
pPrev->next=pCurr;
pCurr->next=pHead;  //最后结点后继指向第一结点
cout<<"结点已经插入"<<endl;
}
return pHead;
    }
//-------插入中间位置
iStart=1;
while(pPrev&&iStart<iSite-1) //直至链表中位置i-1处。
{
pPrev=pPrev->next;       //移动临时结点pPrev的位置至计数i-1处
++iStart;
}
//pCurr= (link)malloc(sizeof(LNode));
pCurr = new LNode;
pCurr->date=iNodeValue;
pCurr->next=pPrev->next;
pPrev->next=pCurr; //此时,pCurr->next指向了pCurr;下一结点插入再循环指向。
cout<<"结点已经插入"<<endl;
//
return pHead;
}
//----------------------------------------删除结点-----------------------
linklist* DeleteListNode(link &L,int iSite,ElemType &iNodeValue,int iLen,BOOL bTypeofLinkList)
{
link pPrev,pCurr,pHead; 
int iStart;
pHead=L;
pPrev=L;
pCurr=pPrev->next;
//----------删除头结点
if (iSite==1)       //删除链表头部第一结点   
{
if (bTypeofLinkList)    //单链表
{
pPrev=pPrev->next;
iNodeValue=pHead->date;
free(pHead);
pHead=pPrev;
cout<<"结点已经删除"<<endl;

else                    //单循环
{
while (pPrev->next!=pHead)
{
pPrev=pPrev->next;
}
//
pPrev->next = pHead->next; 
iNodeValue=pHead->date;
free(pHead);
pHead=pPrev;
cout<<"结点已经删除"<<endl;
}
//
return pCurr;          //返回链表第二个结点地址
}
//--------------删除尾部结点-------------------
    if (iSite==iLen)
    {
if (bTypeofLinkList)   //单链表
{
while (pCurr->next!=NULL)
{
pPrev=pCurr;
pCurr=pCurr->next;
}
//----delete the last node
pPrev->next=NULL;
iNodeValue=pCurr->date;
free(pCurr);
cout<<"结点已经删除"<<endl;

else   //单循环
{
while (pCurr->next!=pHead)
{
pPrev=pCurr;
pCurr=pCurr->next;
}
//
pPrev->next=pHead;
iNodeValue=pCurr->date;
free(pCurr);
cout<<"结点已经删除"<<endl;
}
return pHead;
    }
//-------删除中间位置结点
iStart=1;
while(pPrev&&iStart<iSite-1) //直至链表中位置i-1处。
{
pPrev=pCurr;
pCurr=pCurr->next;
++iStart;
}
//
pPrev->next=pCurr->next;
iNodeValue=pCurr->date;
free(pCurr);
cout<<"结点已经删除\n";
//
return pHead;
}
//--------------------------------查找结点------------------------------
void FindNode(link L,int iNodeValue,BOOL bTypeofLinkList)
{
if(L==NULL)
cout<<"链表未建立,请先构造链表\n" ;
else
{
link pPrev; 
int iStart=1,iCount=0;
pPrev=L;
cout<<"你查找值的位置是:\n " ;       //根据输入的数据值e输出查找到的响应位置值i
//---
if (bTypeofLinkList)   //单链表
{
while(pPrev) //从第1个结点开始比较

if(pPrev->date==iNodeValue)

iCount++;
cout<<iStart<<endl;
}
pPrev=pPrev->next; 
iStart++;
}
cout<<"查找完毕\n";
if(iCount==0)                       //从另一方面讲,此时临时位置还在头结点上,即查找值不在链表中!
cout<<"你查找的值不在链表中!"<<endl;

else   //单循环
{
while(pPrev->next!=L) //从第1个结点开始比较

if(pPrev->date==iNodeValue)

iCount++;
cout<<iStart<<endl;
}
pPrev=pPrev->next; 
iStart++;
}
if(pPrev->date==iNodeValue)

iCount++;
cout<<iStart<<endl;
}
pPrev=pPrev->next; //pPrev返回到第一结点
//----
cout<<"查找完毕\n";
if(iCount==0)                       //从另一方面讲,此时临时位置还在头结点上,即查找值不在链表中!
cout<<"你查找的值不在链表中!"<<endl;
}

}
//---------------------------------链表排序-----------------------------------
//-------使用了最简单的比较法排序:实用,常用;时间复杂度为:T(N)=(N*N-N)/2=O(N*N),N为元素个数
void SortList(link &L,BOOL bTypeofLinkList)   
{
if(L==NULL ||L->next==NULL )   //L=NULL表示未建立链表,L->next=NULL表示链表仅有头结点或者还根本未建立好!
cout<<"链表未建立或是空的,请先构造链表\n" ;
else
{
link pHead,pPrev,pCurr;
pHead=L;
pPrev=L;        //begin with the first node
pCurr=pPrev->next;//the 2nd node
//--
if (bTypeofLinkList)   //单链表
{
while(pPrev!=NULL)
{   
pCurr=pPrev->next;
while(pCurr!=NULL)  //
{
if(pPrev->date>pCurr->date)  //从小到大排序
{   
ElemType temp;
temp=pPrev->date;
pPrev->date=pCurr->date;
pCurr->date=temp; 
}
pCurr=pCurr->next;//该点与其他所有点进行比较
}
pPrev=pPrev->next;    //移动比较基点
}

else //单循环链表
{
while(pPrev->next!=pHead)//end with the last node
{   
pCurr=pPrev->next;
while(pCurr!=pHead)  //返回到第一个结点
{
if(pPrev->date>pCurr->date)  //从小到大排序
{   
ElemType temp;
temp=pPrev->date;
pPrev->date=pCurr->date;
pCurr->date=temp; 
}
pCurr=pCurr->next;//该点与其他所有点进行比较
}
pPrev=pPrev->next;    //移动比较基点
}
}
//-----
cout<<"链表已经排序  \n";
}
}
//--------------------------交换---指针或者引用方式皆可
void Myswap(link &a,link &b)
{
    link temp;
    temp=a;
    a=b;
    b=temp;
}
//---------------------------------链表逆序-------------------------------
//***********交换法
linklist* Swap_Reverse(link pHead,BOOL bTypeofLinkList)

    //---防止传入为空链表
    if ( pHead == NULL||pHead->next==NULL)
    {
        cout<<"链表未建立或是空的,请先构造链表\n" ;
    }
//
link s_pHead=pHead,pPrev,pCurr;
    pPrev = pHead->next; 
pCurr = pPrev;
    pHead->next = NULL;
//---
if (bTypeofLinkList)   //单链表
{
while (pPrev != NULL)   //尾结点后继

Myswap(pPrev->next, pHead); 
Myswap(pHead, pPrev); 


else                   //单循环链表
{
//----------//去掉尾首链接
while (pCurr->next!=s_pHead)//去掉尾首链接
{
pCurr=pCurr->next;
}
pCurr->next=NULL;
//---------- 单链表逆序
while (pPrev != NULL)    //环表头结点

Myswap(pPrev->next, pHead); 
Myswap(pPrev,pHead); 

//--构成单环
        pPrev=pHead->next;
while (pPrev->next!=NULL)
{
pPrev=pPrev->next;
}
pPrev->next=pHead;     //尾首相连
}
//
    return pHead; 

//******直接法
linklist* Direct_Reverse(link pHead,BOOL bTypeofLinkList)

    //---防止传入为空链表
    if ( pHead == NULL||pHead->next==NULL)
    {
        cout<<"链表未建立或是空的,请先构造链表\n" ;
    }
//
link t_pHead=pHead,pPrev(NULL),pCurr(NULL);
    pPrev = t_pHead->next; 
    pHead->next = NULL;
//---
if (bTypeofLinkList)   //单链表
{
while (pPrev != NULL)   //直到尾结点后继

pCurr=pPrev->next;
pPrev->next=t_pHead;
t_pHead=pPrev;
pPrev=pCurr;


else                   //单循环链表
{
while (pPrev != pHead)         //直到返回到头结点

pCurr=pPrev->next;
pPrev->next=t_pHead;
t_pHead=pPrev;
pPrev=pCurr;
}
//---
pPrev->next=t_pHead;     //将尾首相连
}
//
    return t_pHead;                    //返回逆序后的头结点
}
//pHead:约瑟夫环首地址,start:开始报数起点(相对空头结点的偏移位置),amount:环的大小,stop:报数任意上限设置.
//---------------------------------------------------------------------
linklist *JosephusKickout(link pHead,int start,int amount,int stop)
{  
//约瑟夫环是否存在?
if(pHead==NULL||pHead->next==NULL)
{
cout<<"JosephusRing is empty or none!"<<endl;
exit(0);
}
//
link pCurr=NULL,pPrev=NULL; 
pPrev=pHead;
pCurr=pHead->next;
int iStart(1);   //此时n用于设置第一个开始报数时的起点位置start      
    //************退出循环 时pCurr,pPrev分别位于指定位置start 
while(iStart++<start)    
{      
pCurr=pCurr->next;        
pPrev=pPrev->next; 
}   
//***********接下去进行周期性结点删除,直到链表只余一个结点为止*****模拟了全部过程,复杂度O(amount*stop) 
int iNodeNum=1;        //n计算被删除的结点的数量,当n=amount-1时删除结束    
while(iNodeNum++<amount)    //---O(amount*stop)
{        
int temp(1);//temp作为出列循环增计数至stop临时变量   
//----
while(temp++<stop)        
{            
pCurr=pCurr->next;            
pPrev=pPrev->next;        
}        
//temp=stop时删除当前p指向的结点
        cout<<"删除结点:"<<pCurr->date<<"   ";
pPrev->next=pCurr->next;
//释放被删除的结点!
        free(pCurr);       
pCurr=pPrev->next; 
//-------
if (pPrev==pCurr)
{
cout<<endl<<"最后剩下"<<pCurr->date<<endl;
free(pCurr);
break;
}
//-------stop=1时输出删除结点顺序表
if ((stop==1)&&(iNodeNum==amount))
{
cout<<endl<<"最后剩下"<<pCurr->date<<endl;
free(pCurr);
break;
}


}
//
return NULL;

//***************************************测试函数************************************************//无空头结点
int main()
{
link L=NULL,ListRing(NULL);  //L为一个结构体地址类型变量
int iLenofList(0);
int iInputValue(0),iNodeValue(0);
char cInput('n');
BOOL bTypeofLinkList=TRUE;   //default:单链表
//---linklist operation
while (1)
{
PrintPolice();
//---task option    "按2插入结点\n"<<    
cout<<"1----建立链表\n"<<"2----插入结点\n"<<"3----删除结点\n"<<"4----查找结点\n"<<"5----排序结点\n"<<"6----逆序结点\n"
<<"7----Josephus\n"<<"8----清空链表\n"<<"0----退出操作 \n";
PrintPolice();
         //---
cout<<"Input Option:";
cin>>iInputValue;
switch (iInputValue)
{
case 0:
if(L!=NULL)
DestroyLinklist(L,bTypeofLinkList) ;
exit(1);             //exit(0):正常退出;exit(1)或者exit(-1):非正常退出;
break;
case 1:
//------
cout<<"请选择将要创建链表类型: ";
cout<<"1----单链表        2----单循环链表(Josephus Ring)"<<endl;
cout<<"Input Option:";
cin>>iInputValue;
switch (iInputValue)
{
case 1:
bTypeofLinkList=TRUE;
break;
case 2:
bTypeofLinkList=FALSE;
break;
default:break;
}
//------
cout<<"请选择链表创建方式: ";
cout<<"1----选择默认表     2----输入连续数据方式     3----连续输入单个结点数据方式(待增补)"<<endl;
cout<<"Input Option:";
cin>>iInputValue;
switch (iInputValue)
{
case 1:
cout<<"请输入默认链表长度:";
cin>>iInputValue;
while (iInputValue<=0||iInputValue>1000)
{
cout<<"输入数值超出范围,请重新输入:";
cin>>iInputValue;
}
iLenofList=iInputValue;
L=CreateDefaultList(bTypeofLinkList,iInputValue);
cout<<"选择的默认单循环链表为: \n";
DisplayList(L,bTypeofLinkList);
break;
case 2:
L=CreateList(bTypeofLinkList);
cout<<"输入连续数据生成的单循环链表为: \n";
DisplayList(L,bTypeofLinkList);
iLenofList=Length(L,bTypeofLinkList);
cout<<"该链表长度为:"<<iLenofList<<endl;
break;
default:break;
}
break;
case 2:
if (L!=NULL)
{
cout<<"请输入结点插入位置:";
cin>>iInputValue;
while(iInputValue>iLenofList+1 || iInputValue<1) //1:插入链表头部;iLenofList+1:插入链表尾部
{
cout<<"位置错误,重新输入插入位置\n" ;
cin>>iInputValue;
}
//
cout<<"输入结点数据值:";
cin>>iNodeValue;
L=InsertNodeToList(L,iInputValue,iNodeValue,bTypeofLinkList,iLenofList) ;//在链表中某位置插入一个结点,单向链接插入。
iLenofList++;
cout<<"插入结点后数据生成的单链表为: \n";
DisplayList(L,bTypeofLinkList);
cout<<"现在链表长度为:"<<iLenofList<<endl;

else
{
cout<<"链表不存在,请先建链表\n";
}
break;
case 3:
if (L!=NULL)
{
cout<<"请输入删除结点位置:";
cin>>iInputValue;
while(iInputValue>iLenofList || iInputValue<1) //1:链表头部;iLenofList:链表尾部
{
cout<<"位置错误,重新输入删除结点位置\n" ;
cin>>iInputValue;
}
//
L=DeleteListNode(L,iInputValue,iNodeValue,iLenofList,bTypeofLinkList);
cout<<"你删除的是:";
cout<<iNodeValue<<endl ;
iLenofList--;
//
    DisplayList(L,bTypeofLinkList);
cout<<"现在链表长度为:"<<iLenofList<<endl;

else
{
cout<<"链表不存在,请先建链表\n";
}
break;
case 4:
cout<<"输入要查找的值:";
int iInputValue;
cin>>iInputValue;
FindNode(L,iInputValue,bTypeofLinkList);
break;
case 5:
//---对链表排序
SortList(L,bTypeofLinkList);
cout<<"排序后的链表为:\n";
DisplayList(L,bTypeofLinkList);
break;
case 6:
//---交换法对链表逆序
L=Swap_Reverse(L,bTypeofLinkList);
cout<<"交换法逆序后的链表为:\n";
DisplayList(L,bTypeofLinkList);
//---直接法对链表逆序
L=Direct_Reverse(L,bTypeofLinkList);   //*****此法更为简洁--复杂度也较低
cout<<"直接法逆序后的链表为:\n";
DisplayList(L,bTypeofLinkList);
break;
case 7:
if (bTypeofLinkList)
{
cout<<"Josephus Ring has not been built! Please build a ring!"<<endl;
break;
}
//新建一个带空头结点的约瑟夫环,以实现灵活设置起始点、终点的约瑟夫环踢出
ListRing=new LNode;
ListRing->next=L;
//ListRing=L;     //无空头结点不灵活
//-----
cout<<"Please input JosephusRing Kickout startpoint and stoppoint!"<<endl;
cout<<"StartPoint:";
cin>>iInputValue;
cout<<"StopPoint:";
cin>>iNodeValue;
//JosephusRingKickOut(ListRing,iInputValue,iNodeValue);  //无空头结点不灵活
L=JosephusKickout(ListRing,iInputValue,iLenofList,iNodeValue);
break;
case 8:
cout<<"你确实要清空链表吗?y/n:";
cin>>cInput;
cInput=(cInput=='y')?DestroyLinklist(L,bTypeofLinkList):('n');
             //
if (cInput=='y')
{
cout<<"链表已被成功清除!"<<endl;
}
break;
default:break;
}
}
return 0;

}

//

内容也有很多欠缺之处,还请参阅者提出宝贵的意见和评论,方便我们共同交流学习。谢谢!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值