目录
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. 小结
优点:
- 查找前驱节点,不用循环,直接调用前驱指针就行
- 按照位置i ,查找、删除、插入节点的时候,如果i的位置在 链表的后半部分,可以从尾节点往前找。不一定从头部节点开始。