参考自郭帅的博客,但我又改了改,有哪些错误的地方请指出共同讨论。
先说一说我写的双链表的特点
这个双链表有头尾节点的一个概念,遍历的时候不会遍历这两个节点,每个节点都定义了一个数据域,一个指向上一节点的指针和指向下一节点的指针。
下面是代码:list.h
#ifndef LIST_H
#define LIST_H
typedef struct Node *PNode;
typedef int T;
typedef PNode Position;
typedef struct Node{
T data;
PNode before;
PNode next;
}Node;
typedef struct {
PNode head;
PNode tail;
int size;
}DList;
/*分配值为i的节点,并返回节点地址*/
Position MakeNode(T i);
/*构造一个空的双向链表*/
DList* InitList();
/*摧毁一个双向链表*/
void DestroyList(DList *plist);
/*将一个链表置为空表,释放原链表节点空间*/
void ClearList(DList *plist);
/*返回头节点地址*/
Position GetHead(DList *plist);
/*返回尾节点地址*/
Position GetTail(DList *plist);
/*返回链表大小*/
int GetSize(DList *plist);
/*返回p的直接后继位置*/
Position GetNext(Position p);
/*返回p的直接前驱位置*/
Position GetPrevious(Position p);
/*将pnode所指节点插入第一个节点之前*/
PNode InsFirst(DList *plist,PNode pnode);
/*将链表第一个节点删除并返回其地址*/
PNode DelFirst(DList *plist);
/*获得节点的数据项*/
T GetItem(Position p);
/*设置节点的数据项*/
void SetItem(Position p,T i);
/*删除链表中的最后一个节点并返回其地址*/
PNode Remove(DList *plist);
/*在链表中p位置之前插入新节点S*/
PNode InsBefore(DList *plist,Position p,PNode s);
/*在链表中p位置之后插入新节点s*/
PNode InsAfter(DList *plist,Position p,PNode s);
/*返回在链表中第i个节点的位置*/
PNode LocatePos(DList *plist,int i);
/*依次对链表中每个元素调用函数visit()*/
void ListTraverse(DList *plist,void (*visit)());
#endif
list.c
#include<malloc.h>
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include"list.h"
/*构造一个空的双向链表*/
DList *InitList(){
DList *list=(DList*)malloc(sizeof(DList));
PNode head=(PNode)malloc(sizeof(Node));
PNode tail=(PNode)malloc(sizeof(Node));
list->head=head;
list->tail=tail;
/*空链表让头节点的next指针指向尾节点,尾节点的before指针指向头节点*/
list->head->before=NULL;
list->head->next=list->tail;
list->tail->before=list->head;
list->tail->next=NULL;
list->size=0;
return list;
}
/*分配值为i的节点,并返回节点地址*/
Position MakeNode(T i){
PNode p=(PNode)malloc(sizeof(Node));
if(NULL!=p){
p->data=i;
p->before=NULL;
p->next=NULL;
}
return p;
}
/*判断链表是否为空表*/
int IsEmpty(DList* plist){
if(0==plist->size&&plist->head->next==plist->tail&&
plist->tail->before==plist->head){
return 1;
}else
return 0;
}
/*摧毁一个双向链表*/
void DestroyList(DList *plist){
ClearList(plist);
free(plist->head);
free(plist->tail);
free(plist);
}
/*将一个链表置为空表,释放原链表节点空间*/
void ClearList(DList *plist){
PNode p=plist->head->next;
PNode tmp=NULL;
while(!IsEmpty(plist)&&p!=plist->tail){
tmp=p;
free(p);
p=tmp->next;
plist->size--;
}
}
/*返回头节点地址*/
Position GetHead(DList *plist){
return plist->head;
}
/*返回尾节点地址*/
Position GetTail(DList *plist){
return plist->tail;
}
/*返回链表大小*/
int GetSize(DList *plist){
return plist->size;
}
/*返回p的直接后继位置*/
Position GetNext(Position p){
return p->next;
}
/*返回p的直接前驱位置*/
Position GetPrevious(Position p){
return p->before;
}
/*将pnode所指节点插入第一个节点之前*/
PNode InsFirst(DList *plist,PNode pnode){
if(IsEmpty(plist)){
plist->head->next=pnode;
plist->tail->before=pnode;
pnode->before=plist->head;
pnode->next=plist->tail;
}else{
pnode->next=plist->head->next;
pnode->before=plist->head;
plist->head->next->before=pnode;
plist->head->next=pnode;
}
plist->size++;
return pnode;
}
/*将链表第一个节点删除并返回其地址*/
PNode DelFirst(DList *plist){
if(!IsEmpty(plist)){
PNode p=GetHead(plist)->next;
plist->head->next=p->next;
plist->head->next->before=plist->head;
plist->size--;
return plist->head->next;
}else{
return NULL;
}
}
/*获得节点的数据项*/
T GetItem(Position p){
assert(NULL!=p);
return p->data;
}
/*设置节点的数据项*/
void SetItem(Position p,T i){
p->data=i;
}
/*删除链表中的最后一个节点并返回其地址*/
PNode Remove(DList *plist){
if(IsEmpty(plist)){
return NULL;
}else{
PNode p=GetTail(plist)->before;
plist->tail->before=p->before;
plist->tail->before->next=plist->tail;
plist->size--;
return plist->tail->before;
}
}
/*在链表中p位置之前插入新节点S*/
PNode InsBefore(DList *plist,Position p,PNode s){
s->next=p;
s->before=p->before;
if(p==GetHead(plist)){
plist->head=s;
}else{
p->before->next=s;
p->before=s;
}
plist->size++;
return s;
}
/*在链表中p位置之后插入新节点s*/
PNode InsAfter(DList *plist,Position p,PNode s){
s->next=p->next;
s->before=p;
if(p==GetTail(plist)){
plist->tail=s;
}else{
p->next->before=s;
p->next=s;
}
plist->size++;
return s;
}
/*返回在链表中第i个节点的位置*/
PNode LocatePos(DList *plist,int i){
int count=plist->size;
if(IsEmpty(plist)||i>count||i<1){
return NULL;
}else{
PNode p=plist->head->next;
int j;
for(j=0;j<=i;j++){
p=p->next;
}
return p;
}
}
/*依次对链表中每个元素调用函数visit()*/
void ListTraverse(DList *plist,void (*visit)()){
if(IsEmpty(plist)){
exit(0);
}
else{
PNode p=plist->head->next;
while(NULL!=p&&p!=plist->tail){
visit(p->data);
p=p->next;
}
}
}
testList.c
#include<malloc.h>
#include<stdio.h>
#include"list.h"
void print(T i){
printf("数据项是:%d\n",i);
}
main(){
PNode p=NULL;
DList *plist=NULL;
plist=InitList();
p=InsFirst(plist,MakeNode(1));
InsBefore(plist,p,MakeNode(2));
InsAfter(plist,p,MakeNode(3));
printf("p前驱位置的值为%d\n",GetItem(GetPrevious(p)));
printf("p位置的值为%d\n",GetItem(p));
printf("p后继位置的值为%d\n",GetItem(GetNext(p)));
ListTraverse(plist,print);
printf("除了头尾节点该链表共有%d个节点\n",GetSize(plist));
DelFirst(plist);
printf("删除第一个节点后重新遍历输出为:\n");
ListTraverse(plist,print);
Remove(plist);
printf("删除最后一个节点后重新遍历输出为:\n");
ListTraverse(plist,print);
printf("除了头尾节点该链表共有%d个节点\n",GetSize(plist));
DestroyList(plist);
printf("链表已被销毁\n");
}
makefile
OBJECT =list.o testList.o
CC =gcc
CFLAG =-c
testList:$(OBJECT)
$(CC) -o $@ $(OBJECT)
testList.o:testList.c list.c list.h
$(CC) $(CFLAG) -o $@ $<
list.o:list.c list.h
$(CC) $(CFLAG) -o $@ $<
clean:
rm $(OBJECT) -rf
输出结果:
p前驱位置的值为2
p位置的值为1
p后继位置的值为3
数据项是:2
数据项是:1
数据项是:3
除了头尾节点该链表共有3个节点
删除第一个节点后重新遍历输出为:
数据项是:1
数据项是:3
删除最后一个节点后重新遍历输出为:
数据项是:1
除了头尾节点该链表共有1个节点
链表已被销毁
至此,双链表构建完毕,目的在于让自己能重新看看这些代码,有错误的地方指出讨论。