您的位置:首页 > 编程语言 > C语言/C++

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

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

实现源代码如下:

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

}

//

内容也有很多欠缺之处,还请参阅者提出宝贵的意见和评论,方便我们共同交流学习。谢谢!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: