雙向鏈表也叫雙鏈表,是鏈表的一種,它的每個數據結點中都有兩個指針,分別指向直接後繼next和直接前驅prev。所以,從雙向鏈表中的任意一個結點開始,都可以很方便地訪問它的前驅結點和後繼結點。為了標識鏈表的頭和尾,將第一個元素的prev指針和最後一個元素的next指針設置為NULL
要反向遍歷整個雙向鏈表,使用prev指針從尾到頭的順序訪問各個元素,因此為每個元素增加了一個指針的代價,換來的是雙向鏈表更加靈活的訪問。
本文地址:http://www.cnblogs.com/archimedes/p/c-datastruct-dlinklist.html,轉載請注明源地址。
1、dlist_init
void dlist_init(DList *list, void (*destroy)(void *data));
描述:初始化由list指定的雙向鏈表,該操作應該在其他操作之前進行。當調用dlist_destory時,這裡傳入的參數提供了一種釋放動態分配空間的方法
復雜度:O(n)
2、dlist_destroy
void dlist_destroy(DList *list);
描述:銷毀由list指定的雙向鏈表,該操作之後其他操作不能進行。除非重新調用dlist_init
復雜度:O(n)
3、dlist_ins_next
int dlist_ins_next(DList *list, DListElmt *element, const void *data);
描述:將元素插入到由list指定的雙鏈表中element元素之後,當鏈表為空的時候,element為NULL,新的元素包含一個指向data的指針,如果插入成功返回1,否則返回-1
復雜度:O(1)
4、dlist_ins_prev
int dlist_ins_prev(DList *list, DListElmt *element, const void *data);
描述:將元素插入到由list指定的雙鏈表中element元素的前面,當鏈表為空的時候,element為NULL,新的元素包含一個指向data的指針,如果插入成功返回0,否則返回-1
復雜度:O(1)
5、dlist_remove
int dlist_remove(DList *list, DListElmt *element, void **data);
描述:移除由list指定的雙鏈表中element元素,移除操作成功返回0,否則返回-1
復雜度:O(1)
6、dlist_size
int dlist_size(const DList *list);
描述:這是一個宏,用來計算雙鏈表中元素的個數
復雜度:O(1)
7、dlist_head
DListElmt *dlist_head(const DList *list);
描述:這是一個宏,用來返回由list指定的雙鏈表的頭結點
復雜度:O(1)
8、dlist_tail
DListElmt dlist_tail(const DList *list);
描述:這是一個宏,用來返回由list指定的雙鏈表的尾結點
復雜度:O(1)
9、dlist_is_head
int dlist_is_head(const DListElmt *element);
描述:這是一個宏,用來判斷由element元素指定的元素是否為頭結點,如果是返回1,否則返回0
復雜度:O(1)
10、dlist_is_tail
int dlist_is_tail(const DListElmt *element);
描述:這是一個宏,用來判斷由element元素指定的元素是否為尾結點,如果是返回0,否則返回-1
復雜度:O(1)
11、dlist_data
void *dlist_data(const DListElmt *element);
描述:這是一個宏,用來返回由element元素指定的元素的數據域
復雜度:O(1)
12、dlist_next
DListElemt *dlist_next(const DListElmt *element);
描述:這是一個宏,用來返回由element元素指定的元素的後繼結點,如果是返回0,否則返回-1
復雜度:O(1)
13、dlist_prev
DListElemt *dlist_prev(const DListElmt *element);
描述:這是一個宏,用來返回由element元素指定的元素的前驅結點,如果是返回0,否則返回-1
復雜度:O(1)
抽象數據類型的頭文件(list.h):
typedef struct DListElmt_ { //為雙鏈表結點建立結構 void *data; //指向結點的數據域 struct DListElmt_ *prev; //指向結點的前驅結點 struct DListElmt_ *next; //指向結點的前驅結點 } DListElmt; typedef struct DList_ { //建立雙鏈表結構 int size; //元素個數 int (*match)(const void *key1, const void *key2); 匹配函數 void (*destroy)(void *data); 析構函數 DListElmt *head; //指向頭結點 DListElmt *tail; //指向尾結點 } DList; //公共接口 void dlist_init(DList *list, void (*destroy)(void *data)); void dlist_destroy(DList *list); int dlist_ins_next(DList *list, DListElmt *element, const void *data); int dlist_ins_prev(DList *list, DListElmt *element, const void *data); int dlist_remove(DList *list, DListElmt *element, void **data); #define dlist_size(list) ((list)->size) #define dlist_head(list) ((list)->head) #define dlist_tail(list) ((list)->tail) #define dlist_is_head(element) ((element)->prev == NULL ? 1 : 0) #define dlist_is_tail(element) ((element)->next == NULL ? 1 : 0) #define dlist_data(element) ((element)->data) #define dlist_next(element) ((element)->next) #define dlist_prev(element) ((element)->prev) #endif
初始化雙向鏈表:
void dlist_init(DList *list, void (*destroy)(void *data)) { //初始化list list->size = 0; list->destroy = destroy; list->head = NULL; list->tail = NULL; return; }
回收雙向鏈表:
void dlist_destroy(DList *list) { void *data; //移除每個元素 while (dlist_size(list) > 0) { if (dlist_remove(list, dlist_tail(list), (void **)&data) == 0 && list->destroy != NULL) { //調用一個用戶自定義的函數釋放動態分配的內存 list->destroy(data); } } //現在沒有操作了,釋放結構體作為預防措施 memset(list, 0, sizeof(DList)); return; }
插入新節點作為指定結點的直接後繼結點:
參考如下示意圖:
//插入指定元素的後繼 int dlist_ins_next(DList *list, DListElmt *element, const void *data) { DListElmt *new_element; //不允許element元素為NULL,除非list為空. if (element == NULL && dlist_size(list) != 0) return -1; //為element分配空間 if ((new_element = (DListElmt *)malloc(sizeof(DListElmt))) == NULL) return -1; //向鏈表中插入元素 new_element->data = (void *)data; if (dlist_size(list) == 0) { //當鏈表為NULL的時候,插入到頭結點 list->head = new_element; list->head->prev = NULL; list->head->next = NULL; list->tail = new_element; } else { //當鏈表非空的時候 new_element->next = element->next; new_element->prev = element; if (element->next == NULL) list->tail = new_element; else element->next->prev = new_element; element->next = new_element; } //調整鏈表長度 list->size++; return 0; }
插入新節點作為指定結點的直接前驅結點:
//插入指定元素的前驅 int dlist_ins_prev(DList *list, DListElmt *element, const void *data) { DListElmt *new_element; if (element == NULL && dlist_size(list) != 0) //不允許element元素為NULL,除非list為空. return -1; if ((new_element = (DListElmt *)malloc(sizeof(DListElmt))) == NULL) //為element分配空間 return -1; //向鏈表中插入元素 new_element->data = (void *)data; if (dlist_size(list) == 0) { //當鏈表為NULL的時候,插入到頭結點 list->head = new_element; list->head->prev = NULL; list->head->next = NULL; list->tail = new_element; } else { //當鏈表非空的時候插入 new_element->next = element; new_element->prev = element->prev; if (element->prev == NULL) list->head = new_element; else element->prev->next = new_element; element->prev = new_element; } //調整鏈表長度 list->size++; return 0; }
刪除指定結點:
//刪除指定結點 int dlist_remove(DList *list, DListElmt *element, void **data) { //不允許刪除NULL元素或從空表中刪除元素 if (element == NULL || dlist_size(list) == 0) return -1; //從表中刪除元素 *data = element->data; if (element == list->head) { //刪除表頭結點 list->head = element->next; if (list->head == NULL) //如果element元素是尾結點 list->tail = NULL; else element->next->prev = NULL; } else { //刪除表中的結點 element->prev->next = element->next; if (element->next == NULL) list->tail = element->prev; else element->next->prev = element->prev; } //釋放已經分配的結點 free(element); //調整表長 list->size--; return 0; }
//類似//#include "stdafx.h"
#include<iostream.h>
#include<string.h>
#include<iomanip.h>
class stu
{
char name[20];
double age,homephone,telphone;
char sex;
public:
stu(){}
stu(char n[20],char se,double ag,double ho,double te)
{
strcpy(name, n);
age=ag;
homephone=ho;
telphone=te;
}
friend void main();
}; void main()
{
cout<<"請選擇您需要的操作!"<<endl;
cout<<"操作:"<<endl;
cout<<"(0)通訊錄錄入"<<endl;
cout<<"(1)增加人員"<<endl;
cout<<"(2)刪除人員"<<endl;
cout<<"(3)修改數據"<<endl;
cout<<"(4)顯示記錄"<<endl;
cout<<"(5)退出"<<endl;
cout<<"選擇相關操作請輸入相對的括號裡的阿拉伯數字!"<<endl;
stu *s[50];
int i=0;
int j=0;
bool flag2=0;
char p;
do
{
cin>>p;
if((p>='0'&&p<='5'))
flag2=1;
else
cout<<"指令錯誤!請重新輸入:"<<endl;
}while(flag2==0); switch(p)
{ case '0': //(0)通訊錄錄入
{
char name[20];
double age,homephone,telphone;
char sex,c;
do{ cout<<"請輸入姓名:"<<endl;
cin>>name;
cout<<"請輸入性別:"<<endl;
cin>>sex;
cout<<"請輸入年齡:"<<endl;
cin>>age;
cout<<"請輸入家裡的電話號碼:"<<endl;
cin>>homephone;
cout<<"請輸入移動電話號碼:"<<endl;
cin>>telphone;
j++;
s[i]=new stu(name, sex, age......余下全文>>
#include <stdio.h>
#include <stdlib.h>
#define Null 0
#define OverFlow -1
#define OK 0
#define Error -2
typedef int ElemType;
typedef struct node
{
ElemType data;
struct node *next;
}Node,*LinkList;
void Init_LinkList(LinkList *Head_pointer)
{//線性表初始化
*Head_pointer = Null;
}
int Insert_First(LinkList *Head_pointer,ElemType x)
{//采用頭插法建立線性表
Node *p;
p=(Node *)malloc(sizeof Node);
if(p==NULL)
return OverFlow;
p->data=x;
p->next = *Head_pointer;
*Head_pointer = p;
return OK;
}
LinkList Location_LinkList(LinkList Head,ElemType x)
{//查詢鏈表中某結點數據是否存在
LinkList p;
p=Head;
while(p!=Null)
{
if(p->data==x)
break;
p=p->next;
}
return p;
}
int Delete_LinkList(LinkList *Head_pointer,ElemType x)
{//刪除鏈表中的某一結點
Node *p,*q;
p=*Head_pointer;
if(p->data==x)//考慮頭結點就是要刪除的元素
{
*Head_pointer =(*Head_pointer)->next;
free(p);
return OK;
}
else
{
q=p;p=p->next;
while(p!=Null)
{
if(p->data==x)
{
q->next = p->next;
free(p);
return OK;
}
q=p;p=p->next;
}
}
return Error;
}
void Show_LinkList(LinkList Head)
{//遍歷線性表中的元素
LinkList p=Head;
int i=0;
printf("---鏈表打印---\n");
if(p==Null)
printf("空表\n");
while(p!=Null)
{
printf("[%d]:%d\t",i++,p->data);
p=p->next;
}
}
int Length_LinkList(LinkList Head)
{//求鏈表長度
LinkList p=Head;
int sum=0;
while(p!=Null)
{
sum++;
......余下全文>>