【数据结构与算法(c语言)】线性表--双向链表 实际应用

1. 概念

双向链表在单链表中的每个结点中,再设置一个指向其前驱结点的指针域。

2. 图示

在这里插入图片描述

3. 函数

3.1 InitList 初始化链表

原型:Status InitList(LinkList * list)
说明:初始化链表list ,新建一个头结点,将头指针和尾指针都指向这个头结点

Status InitList(LinkList *  list)
{
	list->header = (LNode*)malloc(sizeof(LNode));
	if(list->header == NULL)
		return FALSE;
	else{	
		list->size=0;
		list->header->next = list->header;
		list->header->prior = NULL;	// 头结点的prior前驱置NULL
		list->rear = list->header;   // 尾指针和头指针都指向头结点 
		return TRUE;
	}
}

3.2 插入元素

原型:Status ListInsert(LinkList *list, int i,ElemType elem)
说明:在链表的第i个位置插入元素elem

/* 在链表的第i个位置插入元素elee */
Status ListInsert(LinkList *list, int i,ElemType elem)
{
   
   int j=1;	
   LNode * prevNode,*newNode ;
   if(i<=0)
	return ERROR;
   prevNode=list->header;
   while( (prevNode->next) != NULL && j++<i ){ //如果prevNode->next为NULL,那么说明pervNode->next是最后一个结点了
	   prevNode=prevNode->next;
   }
   
   newNode=(LNode*)malloc(sizeof(LNode));
   if(newNode ==NULL)
	   return ERROR;
   newNode->data=elem;
   newNode->next=prevNode->next; 	 //新节点的next指针指向前驱指针的next;
   if(prevNode->next!=NULL)		 //如果有后驱结点
	 prevNode->next->prior=newNode; //后驱结点的prior指向新生成的结点
   else
	 list->rear=newNode; 		//如果是插入到链表的最后位置,需要将尾指针指向新建的结点   
   prevNode->next=newNode;
   newNode->prior=prevNode;
   list->size++;   
   return OK;   	
}

3.3 ListInsertTail 链表插入元素

原型:Status ListInsertTail(LinkList * list,ElemType elem)
说明:在链表的尾部插入元素elem,一般在新建一个链表的时候经常要使用。

/*在链表的尾部插入元素elem */
Status ListInsertTail(LinkList * list,ElemType elem)
{
	LNode * newNode=(LNode *)malloc(sizeof(LNode));
	if(newNode == NULL)
		return FALSE;
	else { 
		newNode->next=NULL;          //尾部结点的next置空,链表就不是循环链表,如果想将链表变成循环链表,将newNode->next=list->header
		newNode->data = elem;
		list->rear->next = newNode;  //尾部结点的next 指向新结点
		newNode->prior = list->rear; //新增结点的前驱指针指向尾部结点
		list->rear = newNode;	     //尾部指针指向新的结点地址
		list->size++;
		return TRUE;
	}
}

3.4 ListDelete 删除结点

原型:Status ListDelete(LinkList * list,int i)
说明:删除链表list的第i个元素结点。
     在找第i个结点的时候,可以先判断i的位置是在链表的前半部分还是后半部分。
     如果是在前半部分,这从头结点往后找;
     如果是在后半部分,可以从尾部结点往前找,这样就大大的减少了。

Status ListDelete(LinkList * list,int i)
{
	
  int j=1,mid;
  LNode * curNode; // 游标结点
  if(i > list->size)
	  return ERROR;
  mid = list->size/2;//获取list的长度
  
  if(i<= mid){   //如果第i个元素在链表的前半部分,这从头部开始【往后找】第i个结点
	  curNode=list->header->next;//指向头结点后面的第一个结点
    	  while(j++<i)
	 	 curNode=curNode->next;
  }else 	//如果第i个元素在链表的后半部分,这从尾部结点开始【往前找】第i个结点
  {
	  i=list->size-i+1;//将i的次序修改为从尾部开始
	  curNode=list->rear;
	  while(j++<i)
		curNode=curNode->prior;
  }
  curNode->prior->next = curNode->next;  // 前驱结点的next指向当前结点的下一个结点
  if(curNode->next!=NULL)	       // 如果有后驱结点(说明不是最后一个结点)
  curNode->next->prior = curNode->prior;  // 后驱结点的前驱指针指向当前结点的前驱	
  free(curNode);
  list->size--;			       // list的长度减1
  return OK;
}

3.5 GetNode 查找结点

原型:Status GetNode(LinkList list, int i,LNode * nodePtr)
说明:在List中查找第i个结点,并将结点地址存放到nodePtr的指针变量中

/*获取list的第个结点,并将结点地址存放到nodePtr的指针变量中 */
Status GetNode(LinkList list, int i,LNode * nodePtr)
{
	int j=1;
	LNode * curNode= list.header->next;
	if(i<1||i>list.size)
		return ERROR;
	while(j++<i){
		curNode=curNode->next;
	}
	*nodePtr=*curNode;
	return OK;
}

3.6 GetPriorNode 查找前驱结点

原型:Status GetPriorNode(LinkList list ,LNode curNode,LNode *prevNode )
说明:查找curNode的前驱结点 ,如果成功,则将结点地址存放到prevNode中

/*查找curNode的前驱结点 */
Status GetPriorNode(LinkList list ,LNode curNode,LNode *prevNode )
{
	if(curNode.prior==NULL || curNode.prior == list.header)
		return ERROR;
	*prevNode= *(curNode.prior);
		return OK;	
}

3.7 DestoryList 销毁线性表

原型:void DestoryList(LinkList * list)
说明:销毁线性表,将线性表中的所有结点释放内存

/*销毁线性表list*/
void DestoryList(LinkList * list)		
{
	LNode * node;
	while(list->size>0)
	{
	  ListDelete(list,1);//删除链表的第一个元素
	}
	free(list->header);//释放头结点;
	list->header=list->rear=NULL; //将头部和尾部设置为空,防止野指针。至此,链表就被销毁了
}

3.8 ListTraverse 遍历链表

原型:Status ListTraverse(LinkList list,void (*visit)(ElemType))
说明:遍历链表,对链表的每个结点调用Visit函数

/* 遍历链表,对链表的每个结点调用Visit函数 */
Status ListTraverse(LinkList list,void (*visit)(ElemType))		
{
	LNode * curNode;
	if(list.size==0)
		return ERROR;
	 curNode= list.header; //头结点开始
	while((curNode=curNode->next) !=NULL ){
	  Visit(curNode->data);
	}
	printf("\n");
	return OK;
}

3.9 Visit 访问结点的元素

原型:void Visit(ElemType elem)
说明:访问结点元素,此方法就是对元素的一些基本操作,可以根据ElemType的变化而变化。

void Visit(ElemType elem)
{
	printf("%d\t",elem);
}

4 完整代码

4.1 源码

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define OK 	1
#define ERROR 	0
#define TRUE	1
#define	FALSE	0



typedef int Status;	/*	状态码,函数返回的状态码 */
typedef int ElemType;	/*	元素类型,根据需要可以任意修改ElemType的原始类型,此处使用int型	*/

typedef struct LNode
{
	ElemType  data ;	        /*节点数据, */
	struct LNode * prior;
	struct LNode * next;		/*指向下一个节点的指针 */

} LNode ;			/*定义节点类型,并定义一个指向节点的指针 LinkList,作为线性表的开始*/

typedef struct LinkList
{
  LNode * header; //指向头结点的指针
  LNode * rear;   // 指向最后一个结点的指针
  int size;	  //链表的大小
} LinkList;


Status InitList(LinkList * list);		/*初始化线性表list*/
void DestoryList(LinkList * list);		/*销毁线性表list*/

Status ListInsertTail(LinkList * list,ElemType elem);		/*在list的第i个位置插入元素elem*/
Status ListDelete(LinkList * list,int i);	/*在list中删除第i个元素,并将第i个元素存放到elemPtr指针中*/

void Visit(ElemType elem);   /*对elem操作 */ 
Status ListTraverse(LinkList list,void (*visit)(ElemType));		/* 遍历表 */


Status InitList(LinkList *  list)
{
	list->header = (LNode*)malloc(sizeof(LNode));
	if(list->header == NULL)
		return FALSE;
	else{	
		list->size=0;
		list->header->next = list->header;
		list->header->prior = NULL;	// 头结点的prior前驱置NULL
		list->rear = list->header;   // 尾指针和头指针都指向头结点 
		return TRUE;
	}
}

/* 在链表的第i个位置插入元素elee */
Status ListInsert(LinkList *list, int i,ElemType elem)
{
   
   int j=1;	
   LNode * prevNode,*newNode ;
   if(i<=0)
	return ERROR;
   prevNode=list->header;
   while( (prevNode->next) != NULL && j++<i ){ //如果prevNode->next为NULL,那么说明pervNode->next是最后一个结点了
	   prevNode=prevNode->next;
   }
   
   newNode=(LNode*)malloc(sizeof(LNode));
   if(newNode ==NULL)
	   return ERROR;
   newNode->data=elem;
   newNode->next=prevNode->next; 	 //新节点的next指针指向前驱指针的next;
   if(prevNode->next!=NULL){		 //如果有后驱结点
	 prevNode->next->prior=newNode; //后驱结点的prior指向新生成的结点
   }
   else
	 list->rear=newNode; 		//如果是插入到链表的最后位置,需要将尾指针指向新建的结点   

   prevNode->next=newNode;
   newNode->prior=prevNode;
   list->size++;   
   return OK;
    	
}
/*在链表的尾部插入元素elem */
Status ListInsertTail(LinkList * list,ElemType elem)
{
	LNode * newNode=(LNode *)malloc(sizeof(LNode));
	if(newNode == NULL)
		return FALSE;
	else { 
		newNode->next=NULL;          //尾部结点的next置空,链表就不是循环链表,如果想将链表变成循环链表,将newNode->next=list->header
		newNode->data = elem;
		list->rear->next = newNode;  //尾部结点的next 指向新结点
		newNode->prior = list->rear; //新增结点的前驱指针指向尾部结点
		list->rear = newNode;	     //尾部指针指向新的结点地址
		list->size++;
		return TRUE;
	}
}

/*获取list的第个结点,并将结点地址存放到nodePtr的指针变量中 */
Status GetNode(LinkList list, int i,LNode * nodePtr)
{
	int j=1;
	LNode * curNode= list.header->next;
	if(i<1||i>list.size)
		return ERROR;
	while(j++<i){
		curNode=curNode->next;
	}
	*nodePtr=*curNode;
	return OK;
}

/*查找curNode的前驱结点 */
Status GetPriorNode(LinkList list ,LNode curNode,LNode *prevNode )
{
	if(curNode.prior==NULL || curNode.prior == list.header)
		return ERROR;
	*prevNode= *(curNode.prior);
		return OK;	
}





Status ListDelete(LinkList * list,int i)
{
	
  int j=1,mid;
  LNode * curNode; // 游标结点
  if(i > list->size)
	  return ERROR;
  mid = list->size/2;//获取list的长度
  
  if(i<= mid){   //如果第i个元素在链表的前半部分,这从头部开始往后找第i个结点
	  curNode=list->header->next;//指向头结点后面的第一个结点
    	  while(j++<i)
	 	 curNode=curNode->next;
  }else 	//如果第i个元素在链表的后半部分,这从尾部结点开始找第i个结点
  {
	  i=list->size-i+1;//将i的次序修改为从尾部开始
	  curNode=list->rear;
	  while(j++<i)
		curNode=curNode->prior;
  }
  curNode->prior->next = curNode->next;  // 前驱结点的next指向当前结点的下一个结点
  if(curNode->next!=NULL)	       // 如果有后驱结点(说明不是最后一个结点)
  curNode->next->prior = curNode->prior;  // 后驱结点的前驱指针指向当前结点的前驱	
  free(curNode);
  list->size--;			       // list的长度减1
  return OK;
  
}


void DestoryList(LinkList * list)		/*销毁线性表list*/
{
	LNode * node;
	while(list->size>0)
	{
	  ListDelete(list,1);//删除链表的第一个元素
	}
	free(list->header);//释放头结点;
	list->header=list->rear=NULL; //将头部和尾部设置为空,防止野指针。至此,链表就被销毁了
}

void Visit(ElemType elem)
{
	printf("%d\t",elem);
}


Status ListTraverse(LinkList list,void (*visit)(ElemType))		/* 遍历表 */
{
	LNode * curNode;
	if(list.size==0)
		return ERROR;
	 curNode= list.header; //头结点开始
	while((curNode=curNode->next) !=NULL ){
	  Visit(curNode->data);
	}
	printf("\n");
	return OK;

}

int main()
{
	
	LinkList list;
	LNode * nodePtr=(LNode*)malloc(sizeof(LNode));
	InitList(&list);
	ListInsertTail(&list,390);
	ListInsertTail(&list,391);
	ListInsertTail(&list,392);
	ListInsertTail(&list,393);
	ListInsertTail(&list,394);
	printf("\n当前链表:");
	ListTraverse(list,Visit);
	printf("\n插入510元素以后::");
	ListInsert(&list,2,510);
	ListTraverse(list,Visit);

	printf("\n获取第4个元素:");
	if(GetNode(list,4,nodePtr))
		Visit(nodePtr->data);
	printf("\n\n获取前一个结点:");
	if(GetPriorNode(list ,*nodePtr, nodePtr))
		Visit(nodePtr->data);
	DestoryList(&list);
	getchar();
	return 0;
	
}

4.2 数据结果


当前链表:390   391     392     393     394

插入510元素以后::390   510     391     392     393     394

获取第4个元素:392

获取前一个结点:391

5 实际应用测试

可以用循环链表保存 中国的各个朝代,对查询某一个朝代的前一个朝代的时候, 不需要调用从头结点开始找,只需要调用当前结点的前驱指针就立马找到

5.1 修改和新增内容

针对实际应用测试,为了更加直观的 将第4节里的代码稍作修改 。

  • 修改ElemType,由原来的int型,修改成结构性,这样可以保存更多的信息

    typedef struct dynasty
    {  
    	char * name;      // 朝代的名称
    	int startYear;    // 开始时间
    	int endYear;      // 结束时间
    	char * synopsis;   // 朝代简介
    } ElemType;	/*	元素类型,根据需要可以任意修改ElemType的原始类型,此处使用 中国朝代的结构体	*/
    
  • 新建一个结构,保存链表的头指针、尾指针和链表的大小 ,这个结构可以定义链表变量。

    typedef struct LinkList
    {
      LNode * header; //指向头结点的指针
      LNode * rear;   // 指向最后一个结点的指针
      int size;	  //链表的大小
    } LinkList;
    
  • 修改Visit(访问函数),因为ElemType修改了,所以访问也修改了

    void Visit(ElemType elem)
    {
    	printf("%s",elem.name);
    }
    
  • 新增Visit2(访问函数), 可以打印出更多信息

    //打印详情
    void Visit2(ElemType elem)
    {
    	
    	char * startYearStr;
    	char * endYearStr;
    	startYearStr=(char*)malloc(60);
    	endYearStr=(char*)malloc(30);
    	if(elem.startYear<0)
                    sprintf(startYearStr, "公元前%d -- ",abs(elem.startYear));
    	else
    		sprintf(startYearStr,"公元%d -- ",elem.startYear);
    	if(elem.endYear<0)
                    sprintf(endYearStr, "公元前%d",abs(elem.endYear));
    	else 
                    sprintf(endYearStr, "公元%d",elem.endYear);
    
    	printf("%s  %s  开创者:%s \n", elem.name,strcat(startYearStr,endYearStr) ,elem.synopsis);
    	free(startYearStr);
    	free(endYearStr);
    }
    
    
  • 因为朝代比较多,所以把新建链表从main函数抽取出来,形成一个单独的函数 void CreateDynastyList(LinkList * list),

void CreateDynastyList(LinkList * list)
{
	 ElemType newElem;
	InitList(list);

        newElem.name = "夏朝";
        newElem.startYear= -2070;
	newElem.endYear =-1600;
	newElem.synopsis = "大禹";
	ListInsertTail(list,newElem);

	 newElem.name = "商朝";
        newElem.startYear= -1600;
        newElem.endYear = -1046;
        newElem.synopsis = "商汤";
        ListInsertTail(list,newElem);
	
	 newElem.name = "周朝";
        newElem.startYear= -1046;
        newElem.endYear = -221;
        newElem.synopsis = "周武王姬发";
        ListInsertTail(list,newElem);

	 newElem.name = "秦朝";
        newElem.startYear= -221;
        newElem.endYear = -207;
        newElem.synopsis = "秦始皇帝嬴政";
        ListInsertTail(list,newElem);

	 newElem.name = "汉朝";
        newElem.startYear= -202;
        newElem.endYear = 220;
        newElem.synopsis = "汉高祖刘邦";
        ListInsertTail(list,newElem);

	 newElem.name = "三国";
        newElem.startYear= 220;
        newElem.endYear = 280;
        newElem.synopsis = "魏文帝曹丕、汉烈帝刘备、吴大帝孙权";
        ListInsertTail(list,newElem);
	

	 newElem.name = "晋朝";
        newElem.startYear= 266;
        newElem.endYear = 420;
        newElem.synopsis = "晋武帝司马炎";
        ListInsertTail(list,newElem);
	

	 newElem.name = "南北朝";
        newElem.startYear= 386;
        newElem.endYear = 598;
        newElem.synopsis = "宋武帝刘裕、道武帝拓跋珪等";
        ListInsertTail(list,newElem);

	 newElem.name = "隋朝";
        newElem.startYear= 581;
        newElem.endYear = 618;
        newElem.synopsis = "隋文帝杨坚";
        ListInsertTail(list,newElem);

	 newElem.name = "唐朝";
        newElem.startYear= 618;
        newElem.endYear = 907;
        newElem.synopsis = "唐高祖李渊";
        ListInsertTail(list,newElem);

	 newElem.name = "五代十国";
        newElem.startYear= 907;
        newElem.endYear = 979;
        newElem.synopsis = "梁太祖朱温、吴太祖杨行密等";
        ListInsertTail(list,newElem);

	 newElem.name = "宋朝";
        newElem.startYear= 960;
        newElem.endYear = 1279;
        newElem.synopsis = "宋太祖赵匡胤";
        ListInsertTail(list,newElem);

	 newElem.name = "元朝";
        newElem.startYear=1271 ;
        newElem.endYear = 1368;
        newElem.synopsis = "元世祖忽必烈";
        ListInsertTail(list,newElem);

	 newElem.name = "明朝";
        newElem.startYear=1368 ;
        newElem.endYear = 1644;
        newElem.synopsis = "明太祖朱元璋";
        ListInsertTail(list,newElem);

	 newElem.name = "清朝";
        newElem.startYear=1616 ;
        newElem.endYear = 1911;
        newElem.synopsis = "清太祖爱新觉罗.努尔哈赤";
        ListInsertTail(list,newElem);
	
}

5.2 全部源码

/* 
作者:伯恩
时间:2024年5月9日
内容:循环链表实现中国朝代的保存、查询等
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>

#define OK 	1
#define ERROR 	0
#define TRUE	1
#define	FALSE	0



typedef int Status;	/*	状态码,函数返回的状态码 */

typedef struct dynasty
{  
	char * name;      // 朝代的名称
	int startYear;    // 开始时间
	int endYear;      // 结束时间
	char * synopsis;   // 朝代简介
} ElemType;	/*	元素类型,根据需要可以任意修改ElemType的原始类型,此处使用 中国朝代的结构体	*/

typedef struct LNode
{
	ElemType  data ;	        /*节点数据, */
	struct LNode * prior;
	struct LNode * next;		/*指向下一个节点的指针 */

} LNode ;			/*定义节点类型,并定义一个指向节点的指针 LinkList,作为线性表的开始*/

typedef struct LinkList
{
  LNode * header; //指向头结点的指针
  LNode * rear;   // 指向最后一个结点的指针
  int size;	  //链表的大小
} LinkList;


Status InitList(LinkList * list);		/*初始化线性表list*/
void DestoryList(LinkList * list);		/*销毁线性表list*/

Status ListInsertTail(LinkList * list,ElemType elem);		/*在list的第i个位置插入元素elem*/
Status ListDelete(LinkList * list,int i);	/*在list中删除第i个元素,并将第i个元素存放到elemPtr指针中*/

void Visit(ElemType elem);   /*对elem操作 */ 
Status ListTraverse(LinkList list,void (*visit)(ElemType));		/* 遍历表 */


Status InitList(LinkList *  list)
{
	list->header = (LNode*)malloc(sizeof(LNode));
	if(list->header == NULL)
		return FALSE;
	else{	
		list->size=0;
		list->header->next = list->header;
		list->header->prior = NULL;	// 头结点的prior前驱置NULL
		list->rear = list->header;   // 尾指针和头指针都指向头结点 
		return TRUE;
	}

}

/* 在链表的第i个位置插入元素elee */
Status ListInsert(LinkList *list, int i,ElemType elem)
{
   
   int j=1;	
   LNode * prevNode,*newNode ;
   if(i<=0)
	return ERROR;
   prevNode=list->header;
   while( (prevNode->next) != NULL && j++<i ){ //如果prevNode->next为NULL,那么说明pervNode->next是最后一个结点了
	   prevNode=prevNode->next;
   }
   
   newNode=(LNode*)malloc(sizeof(LNode));
   if(newNode ==NULL)
	   return ERROR;
   newNode->data=elem;
   newNode->next=prevNode->next; 	 //新节点的next指针指向前驱指针的next;
   if(prevNode->next!=NULL){		 //如果有后驱结点
	 prevNode->next->prior=newNode; //后驱结点的prior指向新生成的结点
   }
   else
	 list->rear=newNode; 		//如果是插入到链表的最后位置,需要将尾指针指向新建的结点   

   prevNode->next=newNode;
   newNode->prior=prevNode;
   list->size++;   
   return OK;
    	
}

/*在链表的尾部插入元素elem */
Status ListInsertTail(LinkList * list,ElemType elem)
{
	LNode * newNode=(LNode *)malloc(sizeof(LNode));
	if(newNode == NULL)
		return FALSE;
	else { 
		newNode->next=NULL;          //尾部结点的next置空,链表就不是循环链表,如果想将链表变成循环链表,将newNode->next=list->header
		newNode->data = elem;
		list->rear->next = newNode;  //尾部结点的next 指向新结点
		newNode->prior = list->rear; //新增结点的前驱指针指向尾部结点
		list->rear = newNode;	     //尾部指针指向新的结点地址
		list->size++;
		return TRUE;
	}
}

/*获取list的第个结点,并将结点地址存放到nodePtr的指针变量中 */
Status GetNode(LinkList list, int i,LNode * nodePtr)
{
	int j=1;
	LNode * curNode= list.header->next;
	if(i<1||i>list.size)
		return ERROR;
	while(j++<i){
		curNode=curNode->next;
	}
	*nodePtr=*curNode;
	return OK;
}

/*查找curnode的前驱结点 */
Status GetPriorNode(LinkList list ,LNode curNode,LNode *prevNode )
{
	if(curNode.prior==NULL || curNode.prior == list.header)
		return ERROR;
	*prevNode= *(curNode.prior);
		return OK;	
}



Status ListDelete(LinkList * list,int i)
{
	
  int j=1,mid;
  LNode * curNode; // 游标结点
  if(i > list->size)
	  return ERROR;
  mid = list->size/2;//获取list的长度
  
  if(i<= mid){   //如果第i个元素在链表的前半部分,这从头部开始往后找第i个结点
	  curNode=list->header->next;//指向头结点后面的第一个结点
    	  while(j++<i)
	 	 curNode=curNode->next;
  }else 	//如果第i个元素在链表的后半部分,这从尾部结点开始找第i个结点
  {
	  i=list->size-i+1;//将i的次序修改为从尾部开始
	  curNode=list->rear;
	  while(j++<i)
		curNode=curNode->prior;
  }
  curNode->prior->next = curNode->next;  // 前驱结点的next指向当前结点的下一个结点
  if(curNode->next!=NULL)	       // 如果有后驱结点(说明不是最后一个结点)
  curNode->next->prior = curNode->prior;  // 后驱结点的前驱指针指向当前结点的前驱	
  free(curNode);
  list->size--;			       // list的长度减1
  return OK;
  
}


void DestoryList(LinkList * list)		/*销毁线性表list*/
{
	LNode * node;
	while(list->size>0)
	{
	  ListDelete(list,1);//删除链表的第一个元素
	}
	free(list->header);//释放头结点;
	list->header=list->rear=NULL; //将头部和尾部设置为空,防止野指针。至此,链表就被销毁了
}

void Visit(ElemType elem)
{
	printf("%s",elem.name);
}


//打印详情
void Visit2(ElemType elem)
{
	
	char * startYearStr;
	char * endYearStr;
	startYearStr=(char*)malloc(60);
	endYearStr=(char*)malloc(30);
	if(elem.startYear<0)
                sprintf(startYearStr, "公元前%d -- ",abs(elem.startYear));
	else
		sprintf(startYearStr,"公元%d -- ",elem.startYear);
	if(elem.endYear<0)
                sprintf(endYearStr, "公元前%d",abs(elem.endYear));
	else 
                sprintf(endYearStr, "公元%d",elem.endYear);

	printf("%s  %s  开创者:%s \n", elem.name,strcat(startYearStr,endYearStr) ,elem.synopsis);
	free(startYearStr);
	free(endYearStr);
}



Status ListTraverse(LinkList list,void (*visit)(ElemType))		/* 遍历表 */
{
	LNode * curNode;
	if(list.size==0)
		return ERROR;
	curNode = list.header; //头结点开始
	while((curNode=curNode->next) !=NULL ){
	  Visit(curNode->data);
	if(curNode != list.rear)
	  printf(" -- ");
	}
	printf("\n");
	return OK;

}
/*新建朝代链表 */
void CreateDynastyList(LinkList * list)
{
	ElemType newElem;
	InitList(list);

    newElem.name = "夏朝";
    newElem.startYear= -2070;
	newElem.endYear =-1600;
	newElem.synopsis = "大禹";
	ListInsertTail(list,newElem);

	newElem.name = "商朝";
    newElem.startYear= -1600;
    newElem.endYear = -1046;
    newElem.synopsis = "商汤";
    ListInsertTail(list,newElem);
	
	newElem.name = "周朝";
    newElem.startYear= -1046;
    newElem.endYear = -221;
    newElem.synopsis = "周武王姬发";
    ListInsertTail(list,newElem);

	newElem.name = "秦朝";
    newElem.startYear= -221;
    newElem.endYear = -207;
    newElem.synopsis = "秦始皇帝嬴政";
    ListInsertTail(list,newElem);

	newElem.name = "汉朝";
    newElem.startYear= -202;
    newElem.endYear = 220;
    newElem.synopsis = "汉高祖刘邦";
    ListInsertTail(list,newElem);

	newElem.name = "三国";
    newElem.startYear= 220;
    newElem.endYear = 280;
    newElem.synopsis = "魏文帝曹丕、汉烈帝刘备、吴大帝孙权";
    ListInsertTail(list,newElem);
	

	newElem.name = "晋朝";
	newElem.startYear= 266;
	newElem.endYear = 420;
	newElem.synopsis = "晋武帝司马炎";
	ListInsertTail(list,newElem);
	

	newElem.name = "南北朝";
    newElem.startYear= 386;
    newElem.endYear = 598;
    newElem.synopsis = "宋武帝刘裕、道武帝拓跋珪等";
    ListInsertTail(list,newElem);

	newElem.name = "隋朝";
    newElem.startYear= 581;
    newElem.endYear = 618;
    newElem.synopsis = "隋文帝杨坚";
    ListInsertTail(list,newElem);

	newElem.name = "唐朝";
    newElem.startYear= 618;
    newElem.endYear = 907;
    newElem.synopsis = "唐高祖李渊";
    ListInsertTail(list,newElem);

	newElem.name = "五代十国";
    newElem.startYear= 907;
    newElem.endYear = 979;
    newElem.synopsis = "梁太祖朱温、吴太祖杨行密等";
    ListInsertTail(list,newElem);

	newElem.name = "宋朝";
    newElem.startYear= 960;
    newElem.endYear = 1279;
    newElem.synopsis = "宋太祖赵匡胤";
    ListInsertTail(list,newElem);

	newElem.name = "元朝";
    newElem.startYear=1271 ;
    newElem.endYear = 1368;
    newElem.synopsis = "元世祖忽必烈";
    ListInsertTail(list,newElem);

	newElem.name = "明朝";
    newElem.startYear=1368 ;
    newElem.endYear = 1644;
    newElem.synopsis = "明太祖朱元璋";
    ListInsertTail(list,newElem);

	newElem.name = "清朝";
    newElem.startYear=1616 ;
    newElem.endYear = 1911;
    newElem.synopsis = "清太祖爱新觉罗.努尔哈赤";
    ListInsertTail(list,newElem);
	
}


int main()
{
    LinkList list;
    ElemType newElem;
	LNode * nodePtr=(LNode*)malloc(sizeof(LNode));
	CreateDynastyList(&list);
	ListTraverse(list,Visit);
	printf("\n删除周朝以后的朝代:\n");
	ListDelete(&list,3);
	ListTraverse(list,Visit);
	printf("\n插入东周和西周:\n");

	newElem.name = "西周";
    newElem.startYear=-1046 ;
    newElem.endYear = -771;
    newElem.synopsis = "周武王姬发";
    ListInsert(&list,3, newElem);

	newElem.name = "东周";
    newElem.startYear=-770 ;
    newElem.endYear = -256;
    newElem.synopsis = "周平王姬宜臼";
    ListInsert(&list,4,newElem);
	ListTraverse(list,Visit);
	
	printf("\n查找第7个朝代:\n");
	if(GetNode(list,7,nodePtr))
		Visit2(nodePtr->data);

	printf("\n\n在三国之前是:\n");
	if(GetPriorNode(list ,*nodePtr, nodePtr))
		Visit2(nodePtr->data);
	
	DestoryList(&list);
	free(nodePtr);
	getchar();
	return 0;
}

5.3 输出结果

夏朝 -- 商朝 -- 周朝 -- 秦朝 -- 汉朝 -- 三国 -- 晋朝 -- 南北朝 -- 隋朝 -- 唐朝 -- 五代十国 -- 宋朝 -- 元朝 -- 明朝 -- 清朝

删除周朝以后的朝代:
夏朝 -- 商朝 -- 秦朝 -- 汉朝 -- 三国 -- 晋朝 -- 南北朝 -- 隋朝 -- 唐朝 -- 五代十国 -- 宋朝 -- 元朝 -- 明朝 -- 清朝

插入东周和西周:
夏朝 -- 商朝 -- 西周 -- 东周 -- 秦朝 -- 汉朝 -- 三国 -- 晋朝 -- 南北朝 -- 隋朝 -- 唐朝 -- 五代十国 -- 宋朝 -- 元朝 -- 明朝 -- 清朝

查找第7个朝代:
三国  公元220 -- 公元280  开创者:魏文帝曹丕、汉烈帝刘备、吴大帝孙权


在三国之前是:
汉朝  公元前202 -- 公元220  开创者:汉高祖刘邦

6. 小结

优点:

  1. 查找前驱节点,不用循环,直接调用前驱指针就行
  2. 按照位置i ,查找、删除、插入节点的时候,如果i的位置在 链表的后半部分,可以从尾节点往前找。不一定从头部节点开始。
  • 19
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值