书里不全,而且有的写的不好。
我全敲出来,测试过,并且底层函数之间没有互相调用(其实完全可以的,但是我就是不,诶,就是玩儿)
并且把里面一些安排的不好的函数优化了一下.
//双向链表ADT
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#define OK 1
#define ERROR 0
typedef int ElemType;
typedef int Status;
typedef struct Node {
ElemType data;
struct Node* prior;
struct Node* next;
}node, * List;
//小技巧:头结点储存链表长度,还能统一空表和非空表的操作
//函数原型
void Out(ElemType e);//格式化输出
void Print(List L);//正序输出
void PrintDown(List L);//倒序输出
Status InitList(List& L);/*创建空表*/
//Status DestroyList(node* L);//销毁整表
//Status ClearList(node* L);//将L置为空表
bool ListEmpty(List L);//判断是否为空
int ListLength(List L);//返回长度,0和空表都是0
Status GetElem(List L, int i, ElemType& e);//用e返回第i位元素
node* LocateElem(List L, ElemType e, Status(*cmp)(ElemType e,ElemType temp) );//定位到和e满足条件的元素,返回地址,注意编写cmp函数的时候,左边是e,右边是遍历项
node* PriorElem(List L, ElemType cur);//返回cur的前驱,第一个的话就返回L
node* NextElem(List L, ElemType cur);//返回cur的后继,最后一个就返回NULL
Status ListInsert(List L, int i, ElemType e);//把e插入到i位
Status ListDelete(List L, int i, ElemType& e);//删除i位,返回e
Status ListTraverse(List L, Status(*visit)(ElemType& e));//遍历L,执行visit
//函数定义
void Out(ElemType e)
{
printf("%d\t", e);
}
void Print(List L)
{
//本算法考虑了空表情况
node* p = L;
while (p->next)
{
p = p->next;
Out(p->data);
}
}
void PrintDown(List L)
{
//找到尾结点
node* p = L;
while (p->next)
p = p->next;
//倒序输出
while (p != L)
{
Out(p->data);
p = p->prior;
}
}
Status InitList(List &L)
{
//创建头结点赋值并链接
node* head = (node*)malloc(sizeof(node));
if (!head) return ERROR;
head->data = 0; //长度为0
L = head;
head->prior = NULL;
head->next = NULL;
return OK;
}
bool ListEmpty(List L)
{
if (L->data == 0)
return true;
else
return false;
}
int ListLength(List L)
{
if (L)
return L->data;
else
return ERROR;
}
Status GetElem(List L, int i, ElemType& e)
{
//本函数采用先查后判断异常的方式
//令p和index同步采取while循环,因为后面要用index,所以for不如while
node* p = L;
int index = 0;
while (p && index < i)
{
p = p->next;
index++;
}
//到这里,成功则index==i,否则就是i小于1或者大于ListLength
if (!p || i < 1)
return ERROR;
else
{
e = p->data;
return OK;
}
}
node* LocateElem(List L, ElemType e, Status(*cmp)(ElemType e,ElemType temp))
{
//参数中有一个Status(ElemType,ElemType)型的函数指针
node* p = L;
while (p->next)
{
p = p->next;
if (cmp(e, p->data))//直接调用,等价模式
return p;
}
return NULL;
}
node* PriorElem(List L, ElemType cur)
{
//一般来说是用两个指针pre和p,但是其实双向链表更好实现
node* p = L;
while (p->next)
{
p = p->next;
if (cur == p->data)
return p->prior;
}
return NULL;
}
node* NextElem(List L, ElemType cur)
{
node* p = L;
while (p->next)
{
p = p->next;
if (p->data == cur)
return p->next; //不需要判断尾结点,如果是尾结点,就会返回NULL
}
return NULL;
}
Status ListInsert(List L, int i, ElemType e)
{
//本算法为书中优化算法,可以插到i+1位(尾部)
//查找i-1位,所以存在index为0的情况(插到第一个节点)
node* p = L;
int index = 0;
while (p && index < i - 1)
{
p = p->next;
index++;
}
//判断情况
if (!p || i < 1)
return ERROR;
else
{
node* newnode = (node*)malloc(sizeof(node));
if (!newnode) return ERROR;
newnode->data = e;
if (p->next)//判断非表尾
p->next->prior = newnode;
newnode->next = p->next;
p->next = newnode;
newnode->prior = p;
L->data++;
return OK;
}
}
Status ListDelete(List L, int i, ElemType& e)
{
//查找i位
node* p = L;
node* pre_p = p;
int index = 0;
while (p && index < i)
{
pre_p = p;
p = p->next;
index++;
}
//判断情况
if (!p || i < 1)
return ERROR;
else
{
e = p->data;
if (p->next)//判断非尾部
p->next->prior = pre_p;
pre_p->next = p->next;
free(p);
L->data--;
return OK;
}
}
Status ListTraverse(List L, Status(*visit)(ElemType& e))
{
node* p = L;
while (p->next)
{
p = p->next;
if (!visit(p->data))
return ERROR;
}
}
Status visit(ElemType&e)
{
e = e * 10 - 1;
return OK;
}
int main(void)
{
node* L = NULL;
ElemType e = -1;
node* p = NULL;
InitList(L);
for (int i = 1; i <= 5; i++)
ListInsert(L, i, i);
Print(L);
PrintDown(L);
putchar('\n');
//下面随便测试
return 0;
}
要解双向约瑟夫环问题了,所以又在原有基础上改成了双向环表
//双向循环链表ADT
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#define OK 1
#define ERROR 0
typedef int ElemType;
typedef int Status;
typedef struct Node {
ElemType data;
struct Node* prior;
struct Node* next;
}node, * List;
//小技巧:头结点储存链表长度,还能统一空表和非空表的操作
//函数原型
void Out(ElemType e);//格式化输出
void PrintLoop(List L);//正序输出
void PrintLoopDown(List L);//倒序输出
Status InitList(List& L);/*创建空表*/
//Status DestroyList(node* L);//销毁整表
//Status ClearList(node* L);//将L置为空表
bool ListEmpty(List L);//判断是否为空
int ListLength(List L);//返回长度,0和空表都是0
Status GetElem(List L, int i, ElemType& e);//用e返回第i位元素
node* LocateElem(List L, ElemType e, Status(*cmp)(ElemType e,ElemType temp) );//定位到和e满足条件的元素,返回地址,注意编写cmp函数的时候,左边是e,右边是遍历项
//前驱后继可能得根据需求修改了,看你怎么定义前驱后继
node* PriorElem(List L, ElemType cur);//返回cur的前驱,第一个的话就返回L
node* NextElem(List L, ElemType cur);//返回cur的后继,最后一个就返回NULL
Status ListInsert(List L, int i, ElemType e);//把e插入到i位
Status ListDelete(List L, int i, ElemType& e);//删除i位,返回e
Status ListTraverse(List L, Status(*visit)(ElemType& e));//遍历L,执行visit
//函数定义
void Out(ElemType e)
{
printf("%d\t", e);
}
void PrintLoop(List L)
{
node* p = L;
while (p->next != L)//兼容空表
{
p = p->next;
Out(p->data);
}
p = p->next;
while (p->next != L)//兼容空表
{
p = p->next;
Out(p->data);
}
}
void PrintLoopDown(List L)
{
//找到尾结点
node* p = L->prior;
//倒序输出,兼容空表
while (p != L)
{
Out(p->data);
p = p->prior;
}
p = p->prior;
while (p != L)
{
Out(p->data);
p = p->prior;
}
}
Status InitList(List &L)
{
//创建头结点赋值并链接
node* head = (node*)malloc(sizeof(node));
if (!head) return ERROR;
head->data = 0; //长度为0
L = head;
head->prior = head;
head->next = head;
return OK;
}
bool ListEmpty(List L)
{
if (L->data == 0)
return true;
else
return false;
}
int ListLength(List L)
{
if (L)
return L->data;
else
return ERROR;
}
Status GetElem(List L, int i, ElemType& e)
{
//本函数采用先查后判断异常的方式
//令p和index同步采取while循环,因为后面要用index,所以for不如while
node* p = L->next;
int index = 1;
while (p != L && index < i)
{
p = p->next;
index++;
}
//到这里,成功则index==i,否则就是i小于1或者大于ListLength
if (p == L || i < 1)
return ERROR;
else
{
e = p->data;
return OK;
}
}
node* LocateElem(List L, ElemType e, Status(*cmp)(ElemType e,ElemType temp))
{
//参数中有一个Status(ElemType,ElemType)型的函数指针
node* p = L;
while (p->next != L)
{
p = p->next;
if (cmp(e, p->data))//直接调用,等价模式
return p;
}
return NULL;
}
node* PriorElem(List L, ElemType cur)
{
//一般来说是用两个指针pre和p,但是其实双向链表更好实现
node* p = L;
while (p->next != L)
{
p = p->next;
if (cur == p->data)
return p->prior;
}
return NULL;
}
node* NextElem(List L, ElemType cur)
{
node* p = L;
while (p->next != L)
{
p = p->next;
if (p->data == cur)
return p->next;
}
return NULL;
}
Status ListInsert(List L, int i, ElemType e)
{
//本算法为书中优化算法,可以插到i+1位(尾部)
if (i == 1) //第一位特殊处理一下
{
node* p = (node*)malloc(sizeof(node));
if (!p) return ERROR;
p->data = e;
p->next = L->next;
L->next->prior = p;
L->next = p;
p->prior = L;
L->data++;
return OK;
}
else
{
//查找i-1位,不存在index为0的情况(插到第一个节点)
node* p = L->next;
int index = 1;
while (p != L && index < i - 1)
{
p = p->next;
index++;
}
//判断情况
if (p == L || i < 1)
return ERROR;
else
{
node* newnode = (node*)malloc(sizeof(node));
if (!newnode) return ERROR;
newnode->data = e;
p->next->prior = newnode;
newnode->next = p->next;
p->next = newnode;
newnode->prior = p;
L->data++;
return OK;
}
}
}
Status ListDelete(List L, int i, ElemType& e)
{
//查找i位,从1开始
node* p = L->next;
node* pre_p = L;
int index = 1;
while (p != L && index < i)
{
pre_p = p;
p = p->next;
index++;
}
//判断情况
if (p == L || i < 1)
return ERROR;
else
{
e = p->data;
p->next->prior = pre_p;
pre_p->next = p->next;
free(p);
L->data--;
return OK;
}
}
Status ListTraverse(List L, Status(*visit)(ElemType& e))
{
node* p = L;
while (p->next != L)
{
p = p->next;
if (!visit(p->data))
return ERROR;
}
}
//主函数
int main(void)
{
node* L = NULL;
node* p = NULL;
ElemType e = -1;
node* left = NULL;
node* right = NULL;
InitList(L);
for (int i = 1; i <= 5; i++)
ListInsert(L, i, i);
PrintLoop(L);
PrintLoopDown(L);
putchar('\n');
//后面随便测试
return 0;
}