数据结构-C语言实现一个双链表

参考自郭帅的博客,但我又改了改,有哪些错误的地方请指出共同讨论。

 

先说一说我写的双链表的特点

 

 

 

 

 

 

这个双链表有头尾节点的一个概念,遍历的时候不会遍历这两个节点,每个节点都定义了一个数据域,一个指向上一节点的指针和指向下一节点的指针。

下面是代码: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个节点
链表已被销毁

 

至此,双链表构建完毕,目的在于让自己能重新看看这些代码,有错误的地方指出讨论。
 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章