數據結構-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個節點
鏈表已被銷燬

 

至此,雙鏈表構建完畢,目的在於讓自己能重新看看這些代碼,有錯誤的地方指出討論。
 

 

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