线性表作为一种常用的数据结构,在实际中有着广泛的运用。
线性表基本概念
线性表定义
- 线性表(List)是零个或多个数据元素的集合
- 线性表中的数据元素之间是有顺序的
- 线性表中的数据元素个数是有限的
- 线性表中的数据元素的类型必须相同
数学定义
线性表是具有相同类型的 n( ≥ 0)个数据元素的有限序列
(a1, a2,···, an)
ai是表项,n 是表长度
性质
a0为线性表的第一个元素,只有一个后继
an为线性表的最后一个元素,只有一个前驱
除a0和an外的其它元素ai,既有前驱,又有后继
线性表能够逐项访问和顺序存取
线性表的操作
创建线性表
销毁线性表
清空线性表
将元素插入线性表
将元素从线性表中删除
获取线性表中某个位置的元素
获取线性表的长度
线性表在程序中表现为一种特殊的数据类型
线性表的操作在程序中的表现为一组函数
#ifndef __LIST_H_
#define __LIST_H_
typedef void List;
typedef void ListNode;
//创建并且返回一个空的线性表
List* LinkList_Create();
//销毁一个线性表list
void List_Destroy(List* list);
//将一个线性表list中的所有元素清空, 线性表回到创建时的初始状态
void List_Clear(List* list);
//返回一个线性表list中的所有元素个数
int List_Length(List* list);
//向一个线性表list的pos位置处插入新元素node
int List_Insert(List* list, ListNode* node, int pos);
//获取一个线性表list的pos位置处的元素
ListNode* List_Get(List* list, int pos);
//删除一个线性表list的pos位置处的元素 返回值为被删除的元素,NULL表示删除失败
ListNode* List_Delete(List* list, int pos);
#endif
线性表的顺序存储结构
基本概念
设计与实现
-
插入元素算法
判断线性表是否合法
判断插入位置是否合法
把最后一个元素到插入位置的元素后移一个位置
将新元素插入
线性表长度加1 -
获取元素操作
判断线性表是否合法
判断位置是否合法
直接通过数组下标的方式获取元素 -
删除元素算法
判断线性表是否合法
判断删除位置是否合法
将元素取出
将删除位置后的元素分别向前移动一个位置
线性表长度减1
(*.h
)
#ifndef __MY_SEQLIST_H__
#define __MY_SEQLIST_H__
typedef void SeqList;
typedef void SeqListNode;
SeqList* SeqList_Create(int capacity);
void SeqList_Destroy(SeqList* list);
void SeqList_Clear(SeqList* list);
int SeqList_Length(SeqList* list);
int SeqList_Capacity(SeqList* list);
int SeqList_Insert(SeqList* list, SeqListNode* node, int pos);
SeqListNode* SeqList_Get(SeqList* list, int pos);
SeqListNode* SeqList_Delete(SeqList* list, int pos);
#endif
(*.c
)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "seqlist.h"
typedef struct _tag_SeqList
{
int capacity;
int length;
unsigned int *node; //unsigned int array[capacity]
}TSeqList;
SeqList* SeqList_Create(int capacity)
{
TSeqList *ret = NULL;
if (capacity < 0)
{
return NULL;
}
ret = (TSeqList *)malloc(sizeof(TSeqList) + sizeof(unsigned int)*capacity);
if (ret == NULL)
{
return NULL;
}
memset(ret, 0, sizeof(TSeqList) + sizeof(unsigned int)*capacity);
ret->node = (unsigned int *)(ret + 1); //ret向后跳sizeof(TSeqList)
ret->capacity = capacity;
ret->length = 0;
return ret;
}
void SeqList_Destroy(SeqList* list)
{
if (list == NULL)
{
return;
}
free(list);
return;
}
//链表清零
void SeqList_Clear(SeqList* list)
{
TSeqList *tList = NULL;
if (list == NULL)
{
return;
}
tList = (TSeqList *)list;
tList->length = 0;
return;
}
int SeqList_Length(SeqList* list)
{
TSeqList *tList = NULL;
tList = (TSeqList *)list;
if (list == NULL)
{
return -1;
}
return tList->length;
}
//线性表的容量和线性表长度是不一样的
int SeqList_Capacity(SeqList* list)
{
TSeqList *tList = NULL;
tList = (TSeqList *)list;
if (list == NULL)
{
return -1;
}
return tList->capacity;
}
int SeqList_Insert(SeqList* list, SeqListNode* node, int pos)
{
int i = 0;
TSeqList *tList = NULL;
tList = (TSeqList *)list;
if (list == NULL || node == NULL)
{
return -1;
}
//查看是不是满了
if (tList->length >= tList->capacity)
{
return -2;
}
//位置错误判断
if (pos < 0 || pos >= tList->capacity)
{
return -3;
}
//优化的容错。。。
if (pos >= tList->length)
{
pos = tList->length;
}
//插入算法
//从pos位置处开始,把数组后面的元素依此后移
for (i = tList->length; i > pos; i--)
{
//把前的元素往后移
tList->node[i] = tList->node[i - 1];
}
//循环跳出以后,pos正好是,要出入的位置
tList->node[pos] = (unsigned int)node;
tList->length++;
return 0;
}
SeqListNode* SeqList_Get(SeqList* list, int pos)
{
SeqListNode *ret = NULL;
TSeqList *tList = NULL;
tList = (TSeqList *)list;
if (list == NULL || pos < 0 || pos >= tList->length)
{
return NULL;
}
ret = (SeqListNode*)tList->node[pos];
return ret;
}
SeqListNode* SeqList_Delete(SeqList* list, int pos)
{
int i;
TSeqList *tList = NULL;
SeqListNode *ret = NULL;
tList = (TSeqList *)list;
if (list == NULL || pos < 0 || pos >= tList->length)
{
return NULL;
}
//赋给之前,要把元素缓存下来
ret = (SeqListNode *)tList->node[pos];
//删除算法
for (i = pos + 1; i < tList->length; i++)
{
tList->node[i - 1] = tList->node[i];
}
tList->length--;
return ret;
}
(test
)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "seqlist.h"
typedef struct _Teacher
{
char name[64];
int age;
}Teacher;
int main()
{
int i = 0, len = 0;
SeqList *list = NULL;
Teacher t1, t2, t3;
t1.age = 31;
t2.age = 32;
t3.age = 33;
list = SeqList_Create(10);
//头插法
SeqList_Insert(list, (SeqListNode*)&t1, 0);
SeqList_Insert(list, (SeqListNode*)&t2, 0);
SeqList_Insert(list, (SeqListNode*)&t3, 0);
//循环遍历
for (i = 0; i < SeqList_Length(list); i++)
{
Teacher *tmp = (Teacher *)SeqList_Get(list, i);
if (tmp != NULL)
{
printf("age:%d ", tmp->age);
}
}
//循环删除
len = SeqList_Length(list);
for (i = 0; i < len; i++)
{
SeqList_Delete(list, 0);
}
SeqList_Destroy(list);
system("pause");
}
优点和缺点
-
优点:
无需为线性表中的逻辑关系增加额外的空间
可以快速的获取表中合法位置的元素 -
缺点:
插入和删除操作需要移动大量元素
当线性表长度变化较大时难以确定存储空间的容量
线性表的链式存储
基本概念
为了表示每个数据元素与其直接后继元素之间的逻辑关系,每个元素除了存储本身的信息外,还需要存储指示其直接后继的信息
- 表头结点
链表中的第一个结点,包含指向第一个数据元素的指针以及链表自身的一些信息 - 数据结点
链表中代表数据元素的结点,包含指向下一个数据元素的指针和数据元素的信息 - 尾结点
链表中的最后一个数据结点,其下一元素指针为空,表示无后继
设计与实现
在C语言中可以用结构体来定义链表中的指针域
链表中的表头结点也可以用结构体实现
- 插入元素
带头结点、位置从0的单链表
返回链表中第3个位置处,元素的值
LinkListNode* LinkList_Get(LinkList* list, int pos)
{
int i = 0;
TLinkList *tList = (TLinkList *)list;
LinkListNode *current = NULL;
LinkListNode *ret = NULL;
if (list==NULL ||pos<0 || pos>=tList->length)
{
return NULL;
}
current = (LinkListNode *)tList;
for (i=0; i<pos; i++)
{
current = current->next;
}
ret = current->next;
return ret ;
}
返回第三个位置的
移动pos次以后,当前指针指向哪里?
答案:指向位置2,所以需要返回 ret = current->next;
备注:循环遍历时,遍历第1次,指向位置0;遍历第2次,指向位置1;遍历第3次,指向位置2;遍历第n次,指向位置n-1;
所以如果想返回位置n的元素的值,ret = current->next;
- 删除元素
(*.h
)
#ifndef __MY_LINKLIST_H_
#define __MY_LINKLIST_H_
typedef void LinkList;
/*
typedef struct _tag_LinkListNode LinkListNode;
struct _tag_LinkListNode
{
LinkListNode* next;
};
*/
typedef struct _tag_LinkListNode
{
struct _tag_LinkListNode* next;
}LinkListNode;
LinkList* LinkList_Create();
void LinkList_Destroy(LinkList* list);
void LinkList_Clear(LinkList* list);
int LinkList_Length(LinkList* list);
int LinkList_Insert(LinkList* list, LinkListNode* node, int pos);
LinkListNode* LinkList_Get(LinkList* list, int pos);
LinkListNode* LinkList_Delete(LinkList* list, int pos);
#endif
(*.c
)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "linklist.h"
typedef struct _tag_LinkList
{
LinkListNode header;
int length;
}TLinkList;
LinkList* LinkList_Create()
{
TLinkList *ret = (TLinkList *)malloc(sizeof(TLinkList));
if (ret == NULL)
{
return NULL;
}
//memset(ret, 0, sizeof(TLinkList));
ret->header.next = NULL;
ret->length = 0;
return ret;
}
void LinkList_Destroy(LinkList* list)
{
if (list == NULL)
{
return;
}
free(list);
return;
}
void LinkList_Clear(LinkList* list)
{
TLinkList *tList = NULL;
if (list == NULL)
{
return;
}
tList = (TLinkList *)list;
tList->length = 0;
tList->header.next = NULL;
return;
}
int LinkList_Length(LinkList* list)
{
TLinkList *tList = (TLinkList *)list;
if (tList == NULL)
{
return -1;
}
return tList->length;
}
int LinkList_Insert(LinkList* list, LinkListNode* node, int pos)
{
int i = 0;
TLinkList *tList = NULL;
LinkListNode *current = NULL;
tList = (TLinkList *)list;
//准备环境让辅助指针变量 指向链表头节点
current = &tList->header;
for (i = 0; i < pos && (current->next != NULL); i++)
{
current = current->next;
}
//让node节点链接后续链表
node->next = current->next;
//让前边的链表。链接node
current->next = node;
tList->length++;
return 0;
}
LinkListNode* LinkList_Get(LinkList* list, int pos)
{
int i = 0;
TLinkList *tList = NULL;
LinkListNode *current = NULL;
LinkListNode *ret = NULL;
tList = (TLinkList *)list;
if (list == NULL || pos < 0 || pos >= tList->length)
{
return NULL;
}
//准备环境让辅助指针变量 指向链表头节点
current = &tList->header;
for (i = 0; i < pos && (current->next != NULL); i++)
{
current = current->next;
}
ret = current->next;
return ret;
}
LinkListNode* LinkList_Delete(LinkList* list, int pos)
{
int i = 0;
TLinkList *tList = NULL;
LinkListNode *current = NULL;
LinkListNode *ret = NULL;
tList = (TLinkList *)list;
if (list == NULL || pos < 0 || pos >= tList->length)
{
return NULL;
}
//准备环境让辅助指针变量 指向链表头节点
current = &tList->header;
for (i = 0; i < pos && (current->next != NULL); i++)
{
current = current->next;
}
ret = current->next;
//删除算法
current->next = ret->next;
tList->length--;
return ret;
}
(test
)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "linklist.h"
typedef struct Teacher
{
LinkListNode node;
char name[64];
int age;
}Teacher;
int main()
{
Teacher t1, t2, t3;
int length, i = 0;
LinkList *list = NULL;
t1.age = 31;
t2.age = 32;
t3.age = 33;
list = LinkList_Create();
length = LinkList_Length(list);
LinkList_Insert(list, (LinkListNode *)&t1, LinkList_Length(list));
LinkList_Insert(list, (LinkListNode *)&t2, LinkList_Length(list));
LinkList_Insert(list, (LinkListNode *)&t3, LinkList_Length(list));
//遍历链表
for (i = 0; i < LinkList_Length(list); i++)
{
Teacher *tmp = (Teacher *)LinkList_Get(list, i);
if (tmp != NULL)
{
printf("age:%d ", tmp->age);
}
}
while (LinkList_Length(list) > 0)
{
Teacher *tmp = (Teacher *)LinkList_Delete(list, 0);
if (tmp != NULL)
{
printf("age:%d ", tmp->age);
}
}
LinkList_Destroy(list);
system("pause");
return 0;
}
优点和缺点
-
优点:
无需一次性定制链表的容量
插入和删除操作无需移动数据元素 -
缺点:
数据元素必须保存后继元素的位置信息
获取指定数据的元素操作需要顺序访问之前的元素
循环链表
基本概念
将单链表中最后一个数据元素的next指针指向第一个元素
循环链表拥有单链表的所有操作
- 创建链表
- 销毁链表
- 获取链表长度
- 清空链表
- 获取第pos个元素操作
- 插入元素到位置pos
- 删除位置pos处的元素
- 新增功能:游标的定义
在循环链表中可以定义一个“当前”指针,这个指针通常称为游标,可以通过这个游标来遍历链表中的所有元素
获取当前游标指向的数据元素
将游标重置指向链表中的第一个数据元素
将游标移动指向到链表中的下一个数据元素
直接指定删除链表中的某个数据元素
CircleListNode* CircleList_DeleteNode(CircleList* list, CircleListNode* node);
CircleListNode* CircleList_Reset(CircleList* list);
CircleListNode* CircleList_Current(CircleList* list);
CircleListNode* CircleList_Next(CircleList* list);
设计与实现
- 插入元素的分析
- 普通位置插入元素
- 添加第一个元素(第一次插入元素)
- 最后一个位置插入元素
- 第一个位置插入元素
(*.h
)
#ifndef __CIRCLELIST_H_
#define __CIRCLELIST_H_
typedef void CircleList;
/*
typedef struct _tag_CircleListNode CircleListNode;
struct _tag_CircleListNode
{
CircleListNode* next;
};
*/
typedef struct _tag_CircleListNode
{
struct _tag_CircleListNode * next;
}CircleListNode;
CircleList* CircleList_Create();
void CircleList_Destroy(CircleList* list);
void CircleList_Clear(CircleList* list);
int CircleList_Length(CircleList* list);
int CircleList_Insert(CircleList* list, CircleListNode* node, int pos);
CircleListNode* CircleList_Get(CircleList* list, int pos);
CircleListNode* CircleList_Delete(CircleList* list, int pos);
//add
CircleListNode* CircleList_DeleteNode(CircleList* list, CircleListNode* node);
CircleListNode* CircleList_Reset(CircleList* list);
CircleListNode* CircleList_Current(CircleList* list);
CircleListNode* CircleList_Next(CircleList* list);
#endif
(*.c
)
#include <stdio.h>
#include <malloc.h>
#include "CircleList.h"
typedef struct _tag_CircleList
{
CircleListNode header;
CircleListNode* slider;
int length;
} TCircleList;
CircleList* CircleList_Create() // O(1)
{
TCircleList* ret = (TCircleList*)malloc(sizeof(TCircleList));
if (ret == NULL)
{
return NULL;
}
ret->length = 0;
ret->header.next = NULL;
ret->slider = NULL;
return ret;
}
void CircleList_Destroy(CircleList* list) // O(1)
{
if (list == NULL)
{
return;
}
free(list);
}
void CircleList_Clear(CircleList* list) // O(1)
{
TCircleList* sList = (TCircleList*)list;
if (sList == NULL)
{
return;
}
sList->length = 0;
sList->header.next = NULL;
sList->slider = NULL;
}
int CircleList_Length(CircleList* list) // O(1)
{
TCircleList* sList = (TCircleList*)list;
int ret = -1;
if (list == NULL)
{
return ret;
}
ret = sList->length;
return ret;
}
int CircleList_Insert(CircleList* list, CircleListNode* node, int pos) // O(n)
{
int ret = 0, i = 0;
TCircleList* sList = (TCircleList*)list;
if (list == NULL || node == NULL || pos < 0)
{
return -1;
}
CircleListNode* current = (CircleListNode*)sList;
for (i = 0; (i < pos) && (current->next != NULL); i++)
{
current = current->next;
}
//current->next 0号节点的地址
node->next = current->next; //1
current->next = node; //2
//若第一次插入节点
if (sList->length == 0)
{
sList->slider = node;
}
sList->length++;
//若头插法
if (current == (CircleListNode*)sList)
{
//获取最后一个元素
CircleListNode* last = CircleList_Get(sList, sList->length - 1);
last->next = current->next; //3
}
return ret;
}
CircleListNode* CircleList_Get(CircleList* list, int pos) // O(n)
{
TCircleList* sList = (TCircleList*)list;
CircleListNode* ret = NULL;
int i = 0;
if (list == NULL || pos < 0)
{
return NULL;
}
//if( (sList != NULL) && (pos >= 0) && (sList->length > 0) )
{
CircleListNode* current = (CircleListNode*)sList;
for (i = 0; i < pos; i++)
{
current = current->next;
}
ret = current->next;
}
return ret;
}
CircleListNode* CircleList_Delete(CircleList* list, int pos) // O(n)
{
TCircleList* sList = (TCircleList*)list;
CircleListNode* ret = NULL;
int i = 0;
if ((sList != NULL) && (pos >= 0) && (sList->length > 0))
{
CircleListNode* current = (CircleListNode*)sList;
CircleListNode* last = NULL;
for (i = 0; i < pos; i++)
{
current = current->next;
}
//若删除第一个元素
if (current == (CircleListNode*)sList)
{
last = (CircleListNode*)CircleList_Get(sList, sList->length - 1);
}
//求要删除的元素
ret = current->next;
current->next = ret->next;
sList->length--;
//判断链表是否为空
if (last != NULL)
{
sList->header.next = ret->next;
last->next = ret->next;
}
//若删除的元素为游标所指的元素
if (sList->slider == ret)
{
sList->slider = ret->next;
}
//若删除元素后,链表长度为0
if (sList->length == 0)
{
sList->header.next = NULL;
sList->slider = NULL;
}
}
return ret;
}
CircleListNode* CircleList_DeleteNode(CircleList* list, CircleListNode* node) // O(n)
{
TCircleList* sList = (TCircleList*)list;
CircleListNode* ret = NULL;
int i = 0;
if (sList != NULL)
{
CircleListNode* current = (CircleListNode*)sList;
//查找node在循环链表中的位置i
for (i = 0; i < sList->length; i++)
{
if (current->next == node)
{
ret = current->next;
break;
}
current = current->next;
}
//如果ret找到,根据i去删除
if (ret != NULL)
{
CircleList_Delete(sList, i);
}
}
return ret;
}
CircleListNode* CircleList_Reset(CircleList* list) // O(1)
{
TCircleList* sList = (TCircleList*)list;
CircleListNode* ret = NULL;
if (sList != NULL)
{
sList->slider = sList->header.next;
ret = sList->slider;
}
return ret;
}
CircleListNode* CircleList_Current(CircleList* list) // O(1)
{
TCircleList* sList = (TCircleList*)list;
CircleListNode* ret = NULL;
if (sList != NULL)
{
ret = sList->slider;
}
return ret;
}
CircleListNode* CircleList_Next(CircleList* list) // O(1)
{
TCircleList* sList = (TCircleList*)list;
CircleListNode* ret = NULL;
if ((sList != NULL) && (sList->slider != NULL))
{
ret = sList->slider;
sList->slider = ret->next;
}
return ret;
}
(test
)
#include <stdio.h>
#include <stdlib.h>
#include "CircleList.h"
struct Value
{
CircleListNode circlenode;
int v;
};
int main()
{
int i = 0;
CircleList* list = CircleList_Create();
struct Value v1;
struct Value v2;
struct Value v3;
struct Value v4;
struct Value v5;
struct Value v6;
struct Value v7;
struct Value v8;
v1.v = 1;
v2.v = 2;
v3.v = 3;
v4.v = 4;
v5.v = 5;
v6.v = 6;
v7.v = 7;
v8.v = 8;
CircleList_Insert(list, (CircleListNode*)&v1, 0);
CircleList_Insert(list, (CircleListNode*)&v2, 0);
CircleList_Insert(list, (CircleListNode*)&v3, 0);
CircleList_Insert(list, (CircleListNode*)&v4, 0);
for (i = 0; i < 2 * CircleList_Length(list); i++)
{
struct Value* pv = (struct Value*)CircleList_Get(list, i);
printf("%d
", pv->v);
}
while (CircleList_Length(list) > 0)
{
CircleList_Delete(list, 0);
}
printf("
");
CircleList_Destroy(list);
system("pause");
return 0;
}
优点和缺点
-
优点:功能强了。
循环链表只是在单链表的基础上做了一个加强
循环链表可以完全取代单链表的使用
循环链表的Next和Current操作可以高效的遍历链表中的所有元素 -
缺点:
代码复杂度提高了
约瑟夫问题-循环链表典型应用
n 个人围成一个圆圈,首先第 1 个人从 1 开始一个人一个人顺时针报数,报到第 m 个人,令其出列。然后再从下一 个人开始从 1 顺时针报数,报到第 m 个人,再令其出列,···,如此下去,求出列顺序
#include <stdio.h>
#include <stdlib.h>
#include "CircleList.h"
struct Value
{
CircleListNode header;
int v;
};
void main()
{
int i = 0;
CircleList* list = CircleList_Create();
struct Value v1, v2, v3, v4, v5, v6, v7, v8;
v1.v = 1; v2.v = 2; v3.v = 3; v4.v = 4;
v5.v = 5; v6.v = 6; v7.v = 7; v8.v = 8;
CircleList_Insert(list, (CircleListNode*)&v1, CircleList_Length(list));
CircleList_Insert(list, (CircleListNode*)&v2, CircleList_Length(list));
CircleList_Insert(list, (CircleListNode*)&v3, CircleList_Length(list));
CircleList_Insert(list, (CircleListNode*)&v4, CircleList_Length(list));
CircleList_Insert(list, (CircleListNode*)&v5, CircleList_Length(list));
CircleList_Insert(list, (CircleListNode*)&v6, CircleList_Length(list));
CircleList_Insert(list, (CircleListNode*)&v7, CircleList_Length(list));
CircleList_Insert(list, (CircleListNode*)&v8, CircleList_Length(list));
for (i = 0; i < CircleList_Length(list); i++)
{
struct Value* pv = (struct Value*)CircleList_Next(list);
printf("%d
", pv->v);
}
printf("
");
//重置游标
CircleList_Reset(list);
while (CircleList_Length(list) > 0)
{
struct Value* pv = NULL;
for (i = 1; i < 3; i++)
{
CircleList_Next(list);
}
pv = (struct Value*)CircleList_Current(list);
printf("%d
", pv->v);
CircleList_DeleteNode(list, (CircleListNode*)pv);
}
CircleList_Destroy(list);
system("pause");
}
双向链表
基本概念
单链表的结点都只有一个指向下一个结点的指针
单链表的数据元素无法直接访问其前驱元素
逆序访问单链表中的元素是极其耗时的操作
len = LinkList_Length(list);
for (i=len-1; len>=0; i++) //O(n)
{
LinkListNode *p = LinkList_Get(list, i); //O(n)
//访问数据元素p中的元素
}
双向链表的定义
在单链表的结点中增加一个指向其前驱的pre指针
双向链表拥有单链表的所有操作
- 创建链表
- 销毁链表
- 获取链表长度
- 清空链表
- 获取第pos个元素操作
- 插入元素到位置pos
- 删除位置pos处的元素
设计与实现
-
插入操作
-
删除操作
双向链表的新操作
获取当前游标指向的数据元素
将游标重置指向链表中的第一个数据元素
将游标移动指向到链表中的下一个数据元素
将游标移动指向到链表中的上一个数据元素
直接指定删除链表中的某个数据元素
DLinkListNode* DLinkList_DeleteNode(DLinkList* list, DLinkListNode* node);
DLinkListNode* DLinkList_Reset(DLinkList* list);
DLinkListNode* DLinkList_Current(DLinkList* list);
DLinkListNode* DLinkList_Next(DLinkList* list);
DLinkListNode* DLinkList_Pre(DLinkList* list);
(*.h
)
#ifndef __MY_DLINKLIST_H_
#define __MY_DLINKLIST_H_
typedef void DLinkList;
/*
typedef struct _tag_DLinkListNode DLinkListNode;
struct _tag_DLinkListNode
{
DLinkListNode* next;
DLinkListNode* pre;
};
*/
typedef struct _tag_DLinkListNode
{
struct _tag_DLinkListNode* next;
struct _tag_DLinkListNode * pre;
}DLinkListNode;
DLinkList* DLinkList_Create();
void DLinkList_Destroy(DLinkList* list);
void DLinkList_Clear(DLinkList* list);
int DLinkList_Length(DLinkList* list);
int DLinkList_Insert(DLinkList* list, DLinkListNode* node, int pos);
DLinkListNode* DLinkList_Get(DLinkList* list, int pos);
DLinkListNode* DLinkList_Delete(DLinkList* list, int pos);
//add
DLinkListNode* DLinkList_DeleteNode(DLinkList* list, DLinkListNode* node);
DLinkListNode* DLinkList_Reset(DLinkList* list);
DLinkListNode* DLinkList_Current(DLinkList* list);
DLinkListNode* DLinkList_Next(DLinkList* list);
DLinkListNode* DLinkList_Pre(DLinkList* list);
#endif
(*.c
)
#include <stdio.h>
#include <malloc.h>
#include "DLinkList.h"
typedef struct _tag_DLinkList
{
DLinkListNode header;
DLinkListNode* slider;
int length;
} TDLinkList;
DLinkList* DLinkList_Create()
{
TDLinkList* ret = (TDLinkList*)malloc(sizeof(TDLinkList));
if (ret != NULL)
{
ret->length = 0;
ret->header.next = NULL;
ret->header.pre = NULL;
ret->slider = NULL;
}
return ret;
}
void DLinkList_Destroy(DLinkList* list)
{
if (list != NULL)
{
free(list);
}
}
void DLinkList_Clear(DLinkList* list)
{
TDLinkList* sList = (TDLinkList*)list;
if (sList != NULL)
{
sList->length = 0;
sList->header.next = NULL;
sList->header.pre = NULL;
sList->slider = NULL;
}
}
int DLinkList_Length(DLinkList* list)
{
int ret = -1;
TDLinkList* sList = (TDLinkList*)list;
if (sList != NULL)
{
ret = sList->length;
}
return ret;
}
//大家一定要注意:教科书不会告诉你 项目上如何用;哪些点是项目的重点
int DLinkList_Insert(DLinkList* list, DLinkListNode* node, int pos)
{
int ret = 0, i = 0;
TDLinkList* sList = (TDLinkList*)list;
if (list == NULL || node == NULL || pos < 0)
{
return -1;
}
{
DLinkListNode* current = (DLinkListNode*)sList;
DLinkListNode* next = NULL; //需要增加next指针
for (i = 0; (i < pos) && (current->next != NULL); i++)
{
current = current->next;
}
next = current->next;
//步骤1-2
current->next = node;
node->next = next;
//步骤3-4
if (next != NULL) //当链表插入第一个元素,需要特殊处理
{
next->pre = node;
}
node->pre = current;
if (sList->length == 0)
{
sList->slider = node; //当链表插入第一个元素处理游标
}
//若在0位置插入,需要特殊处理 新来结点next前pre指向null
if (current == (DLinkListNode*)sList)
{
node->pre = NULL;
}
sList->length++;
}
return ret;
}
DLinkListNode* DLinkList_Get(DLinkList* list, int pos)
{
int i = 0;
TDLinkList* sList = (TDLinkList*)list;
DLinkListNode* ret = NULL;
if ((sList != NULL) && (0 <= pos) && (pos < sList->length))
{
DLinkListNode* current = (DLinkListNode*)sList;
for (i = 0; i < pos; i++)
{
current = current->next;
}
ret = current->next;
}
return ret;
}
//插入第一个节点
//删除的是最后一个结点,该是如何处理
DLinkListNode* DLinkList_Delete(DLinkList* list, int pos)
{
int i = 0;
TDLinkList* sList = (TDLinkList*)list;
DLinkListNode* ret = NULL;
if (sList == NULL || pos < 0)
{
return NULL;
}
//if( (sList != NULL) && (0 <= pos) && (pos < sList->length) )
{
DLinkListNode* current = (DLinkListNode*)sList;
DLinkListNode* next = NULL; //需要增加next指针
for (i = 0; i < pos; i++)
{
current = current->next;
}
ret = current->next;
next = ret->next;
//步骤1
current->next = next;
//步骤2
if (next != NULL)//需要特殊处理
{
next->pre = current;
if (current == (DLinkListNode*)sList) //若第0个位置,需要特殊处理
{
next->pre = NULL;
}
}
if (sList->slider == ret)
{
sList->slider = next;
}
sList->length--;
}
return ret;
}
DLinkListNode* DLinkList_DeleteNode(DLinkList* list, DLinkListNode* node)
{
int i = 0;
TDLinkList* sList = (TDLinkList*)list;
DLinkListNode* ret = NULL;
if (sList != NULL)
{
DLinkListNode* current = (DLinkListNode*)sList;
for (i = 0; i < sList->length; i++)
{
if (current->next == node)
{
ret = current->next;
break;
}
current = current->next;
}
if (ret != NULL)
{
DLinkList_Delete(sList, i);
}
}
return ret;
}
DLinkListNode* DLinkList_Reset(DLinkList* list)
{
TDLinkList* sList = (TDLinkList*)list;
DLinkListNode* ret = NULL;
if (sList != NULL)
{
sList->slider = sList->header.next;
ret = sList->slider;
}
return ret;
}
DLinkListNode* DLinkList_Current(DLinkList* list)
{
TDLinkList* sList = (TDLinkList*)list;
DLinkListNode* ret = NULL;
if (sList != NULL)
{
ret = sList->slider;
}
return ret;
}
DLinkListNode* DLinkList_Next(DLinkList* list)
{
TDLinkList* sList = (TDLinkList*)list;
DLinkListNode* ret = NULL;
if ((sList != NULL) && (sList->slider != NULL))
{
ret = sList->slider;
sList->slider = ret->next;
}
return ret;
}
DLinkListNode* DLinkList_Pre(DLinkList* list)
{
TDLinkList* sList = (TDLinkList*)list;
DLinkListNode* ret = NULL;
if ((sList != NULL) && (sList->slider != NULL))
{
ret = sList->slider;
sList->slider = ret->pre;
}
return ret;
}
(test
)
#include <stdio.h>
#include <stdlib.h>
#include "DLinkList.h"
struct Value
{
DLinkListNode node;
int v;
};
int main()
{
int i = 0;
DLinkList* list = DLinkList_Create();
struct Value* pv = NULL;
struct Value v1, v2, v3, v4, v5;
v1.v = 1; v2.v = 2; v3.v = 3;
v4.v = 4; v5.v = 5;
DLinkList_Insert(list, (DLinkListNode*)&v1, DLinkList_Length(list));
DLinkList_Insert(list, (DLinkListNode*)&v2, DLinkList_Length(list));
DLinkList_Insert(list, (DLinkListNode*)&v3, DLinkList_Length(list));
DLinkList_Insert(list, (DLinkListNode*)&v4, DLinkList_Length(list));
DLinkList_Insert(list, (DLinkListNode*)&v5, DLinkList_Length(list));
for(i=0; i<DLinkList_Length(list); i++)
{
pv = (struct Value*)DLinkList_Get(list, i);
printf("%d
", pv->v);
}
printf("
");
DLinkList_Delete(list, DLinkList_Length(list)-1);
DLinkList_Delete(list, 0);
//DLinkList_Delete(list, 3);
for(i=0; i<DLinkList_Length(list); i++)
{
pv = (struct Value*)DLinkList_Next(list);
printf("%d
", pv->v);
}
printf("
");
DLinkList_Reset(list);
DLinkList_Next(list);
pv = (struct Value*)DLinkList_Current(list);
printf("%d
", pv->v);
DLinkList_DeleteNode(list, (DLinkListNode*)pv);
pv = (struct Value*)DLinkList_Current(list);
printf("%d
", pv->v);
DLinkList_Pre(list);
pv = (struct Value*)DLinkList_Current(list);
printf("%d
", pv->v);
printf("Length: %d
", DLinkList_Length(list));
DLinkList_Destroy(list);
system("pause");
return 0;
}
优点和缺点
-
优点:双向链表在单链表的基础上增加了指向前驱的指针
功能上双向链表可以完全取代单链表的使用
循环链表的Next,Pre和Current操作可以高效的遍历链表中的所有元素 -
缺点:代码复杂