參考自郭帥的博客,但我又改了改,有哪些錯誤的地方請指出共同討論。
先說一說我寫的雙鏈表的特點
這個雙鏈表有頭尾節點的一個概念,遍歷的時候不會遍歷這兩個節點,每個節點都定義了一個數據域,一個指向上一節點的指針和指向下一節點的指針。
下面是代碼: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個節點
鏈表已被銷燬
至此,雙鏈表構建完畢,目的在於讓自己能重新看看這些代碼,有錯誤的地方指出討論。