/* run this program using the console pauser or add your own getch, system("pause") or input loop */
// 用到的库文件
#include <stdio.h> // printf();scanf()
#include <stdlib.h> // exit()
#include <malloc.h> // malloc()
#include <time.h> // srand((unsigned)time(NULL));
// 函数结果状态代码
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
// Status是函数的类型,其值是函数结果状态代码
typedef int Status;
// #define ElemType int // 也可以用宏定义确定ElemType类型
typedef int ElemType;
// -----双向链表-----
typedef struct DuLNode {
ElemType data; // 数据域
struct DuLNode *prior; // 指向前驱
struct DuLNode *next; // 指向后继
} DuLNode, *DuLinkList;
// 操作结果:构造一个空的线性表L。
Status InitList_DuL(DuLinkList &L) {
if(L != NULL)
{
printf("线性表已存在!!!");
return INFEASIBLE; // 返回-1
}
L = (DuLinkList)malloc(sizeof(DuLNode));
if(!L) { // 存储分配失败
printf("初始化失败!!!");
exit(OVERFLOW); // exit(-2)程序异常退出
}
L->next = L; // 先建立一个带头结点的双向链表,
L->prior = L; // 并使头结点2个指针域指向本身(即头指针L)
return OK;
}// InitList_DuL
// 操作结果:销毁线性表L。
Status DestroyList_DuL(DuLinkList &L) {
if(!L)
{
printf("线性表未初始化。");
return INFEASIBLE;
}
DuLinkList p = L->next, ptmp; // p指向线性表第一个结点(线性表为空表时,指向头结点)
while(p != L) { // p指向头结点时,循环停止
ptmp = p->next;
free(p); // 释放每个数据结点的指针域
p = ptmp;
}
free(L); // 释放头结点
L = NULL;
return OK;
}// DestroyList_DuL
// 操作结果:将L重置为空表。
Status ClearList_DuL(DuLinkList &L) {
if(!L)
{
printf("线性表未初始化。");
return INFEASIBLE;
}
if(L->next == L)
{
printf("线性表本已空!!!");
return INFEASIBLE;
}
DuLinkList p = L->next, ptmp; // p指向线性表第一个结点
while(p != L) { // p指向头结点时,循环停止
ptmp = p->next;
free(p); // 释放每个结点的指针域
p = ptmp;
}
L->next = L; // 头结点指针域指向本身
return OK;
}// ClearList_DuL
// 操作结果:若L为空表,返回TRUE,否则返回FALSE
Status ListEmpty_DuL(DuLinkList L) {
if(!L)
{
printf("线性表未初始化。");
return INFEASIBLE; // 返回-1
}
else if(L->next == L)
{
printf("线性表为空。");
return TRUE; // 返回1
}
else
{
printf("线性表非空。");
return FALSE; // 返回0
}
}// ListEmpty_DuL
// 操作结果:返回L中数据元素个数。
int ListLength_DuL(DuLinkList L) {
if(!L)
{
printf("线性表未初始化。");
return INFEASIBLE; // 返回-1
}
int nElem = 0;
DuLinkList p = L->next; // p指向第一个结点(空表时,指向头结点)
while(p != L) {
nElem ++;
p = p->next;
}
return nElem;
}// ListLength
// 操作结果:用e返回L中第i个数据元素的值。1≤i≤ListLength(L) 。
Status GetElem_DuL(DuLinkList L, int i, ElemType &e) {
if(!L) {
printf("线性表未初始化。");
return INFEASIBLE; // 返回-1
}
DuLinkList p = L->next; // p指向第一个结点(空表时,指向头结点)
int j = 1; // j为计数器,统计当p指向第i个数据时,表中已有元素个数
while ( (p->next != L) && j<i ) // 顺指针向后查找,直到p指向第i个元素或p指向头结点
{
p = p->next;
++j;
}
if ( p==L || j<i || i<1 ) // p == L 指向头结点,说明表为空表。j<i i的值大于表中现有元素个数。 i<1 传入参数有问题。
{
return ERROR; // 第i个元素不存在
}
e = p->data; // 取第i个元素
return OK;
}// GetElem_DuL 算法2.8更改
// 操作结果:用p返回L中第i个数据元素的指针。1≤i≤ListLength(L)。
DuLinkList GetElemP_DuL(DuLinkList L, int i) {
DuLinkList p = L; // p指向头结点
int j = 0; // j为计数器,统计当p指向第i个结点时,表中已有元素个数
// p->next == L,表为空。i>j,超出查找范围
while ( (p->next != L) && j<i ) // 顺指针向后查找,直到p指向第i个元素或p指向头结点
{
p = p->next;
++j;
}
if ( i<1 || i>j+1 ) // i>j+1 i的值大于表长+1。 i<1 传入参数有问题。
{
return NULL; // i大于表长加1时,p=NULL
}
// 插入时:i=表长加1,返回头结点;
if ( i==j+1 )
{
return L;
}
return p; // i<表长加1时,p指向第i个结点;
}// GetElem_DuL 算法2.8更改
// 操作结果:返回L中第1个与e满足compare()(数据元素判定函数)的数据元素的位序,若这样的数据元素不存在,则返回值为0。
Status compare(ElemType listElem, ElemType e) {
return listElem == e ? TRUE : FALSE;
}// Compare
int LocateElem_DuL(DuLinkList L, ElemType e, Status (*pfn_compare)(ElemType, ElemType)) {
if(!L) {
printf("线性表未初始化。");
return INFEASIBLE; // 返回-1
}
int pos = 1;
DuLinkList p = L->next; // p指向第一个结点(空表时,指向头结点)
while( (p != L) && !(*pfn_compare)(p->data, e) ) {
++ pos;
p = p->next; // 指针后移p->next = L时,循环回到头结点
}
// p == L 指向头结点,说明表为空表。pos>ListLength_DuL(L) pos的值大于表中现有元素个数。
if( (p == L) || pos>ListLength_DuL(L) )
{
return ERROR; // 返回0
}
return pos;
}// LocateElem_DuL
// 操作结果:若cur_e是L的数据元素,则用pre_e返回它的前驱,否则操作失败,pre_e无定义。
Status PriorElem_DuL(DuLinkList L, ElemType cur_e, ElemType &pre_e) {
int i = LocateElem_DuL(L, cur_e, compare);
// cur_e为第一个元素,其前驱为最后一个元素
if(i==0 || i==1)
{
GetElem_DuL(L, ListLength_DuL(L), pre_e);
return OK;
}
GetElem_DuL(L, i-1, pre_e);
return OK;
}// PriorElem_DuL
// 操作结果:若cur_e是L的数据元素,则用next_e返回它的后继,否则操作失败,pre_e无定义。
Status NextElem_Sq(DuLinkList L, ElemType cur_e, ElemType &next_e) {
int i = LocateElem_DuL(L, cur_e, compare);
// cur_e为最后一个元素,其后继为第一个元素
if(i==0 || i==ListLength_DuL(L))
{
GetElem_DuL(L, 1, next_e);
return OK;
}
GetElem_DuL(L, i+1, next_e);
return OK;
}// NextElem_Sq
// 操作结果:在L中第pos个位置插入新的元素e,L的长度加1。1≤pos≤ListLength(L)+1。
Status ListInsert_DuL(DuLinkList &L, int pos, ElemType e) {
if(!L) { // 线性表是否存在
printf("线性表未初始化。");
return INFEASIBLE;
}
DuLinkList p, s;
if( !(p = GetElemP_DuL(L, pos) ) ) { // 在L中确定插入位置指针p
printf("插入位置不合法。");
return ERROR; // i等于表长加1时,p指向头结点;i大于表长加1时,p=NULL
}
if( !(s = (DuLinkList)malloc(sizeof(DuLNode)) ) ) {// 生成新结点
printf("存储分配失败。");
return ERROR;
}
s->data = e; // 将插入的元素值 赋给 新生成结点的数据域
s->prior = p->prior; // 插入结点 反向指向 前驱
p->prior->next = s; // 前驱 指向 插入结点
s->next = p; // 插入结点 指向 后继
p->prior = s; // 后继 反向指向 插入结点
printf("插入的位置:%d, 插入的元素:%d", pos, e);
return OK;
}// ListInsert_DuL 算法2.18更改
// 操作结果:删除L的第pos个数据元素,并用e返回其值,L的长度减1。1≤pos≤ListLength(L)。
Status ListDelete_DuL(DuLinkList &L, int pos, ElemType &e) {
if(!L) { // 线性表是否存在
printf("线性表未初始化。");
return INFEASIBLE;
}
DuLinkList p;
if( !(p = GetElemP_DuL(L, pos)) || p==L) { // 在L中确定第i个元素的位置指针p
return ERROR; // p=NULL或p=L时,即第pos个元素不存在
}
e = p->data; // 要删除结点的数据域,赋给e
p->prior->next = p->next; // 删除结点前驱 指向 删除结点后继
p->next->prior = p->prior; // 删除结点后继 指向 删除结点前驱
free(p); // 释放指针变量p
return OK;
}// ListDelete_DuL 算法2.19更改
// 操作结果:依次对L的每个数据元素调用函数visit()。一旦vistit()失败,刚操作失败。
Status visit(ElemType e) {
printf("%d <-> ", e);
return OK;
}
Status ListTraverse_DuL(DuLinkList L, Status (*pfn_visit)(ElemType)) {
if(!L) {
printf("线性表未初始化。");
return INFEASIBLE;
}
if(L->next == L) {
printf("线性表为空表。");
return ERROR;
}
DuLinkList p = L->next; // p指向第一个结点
while(p != L) {
visit(p->data);
p = p->next;
}
return OK;
}// ListTraverse
// 创建随机表,包含10个随机数(头插法)。
void CreateList_DuL_10(DuLinkList &L) {
// 提供随机数种子
srand((unsigned)time(NULL));
// 生成头结点
L = (DuLinkList)malloc(sizeof(DuLNode));
if(!L) {
printf("存储分配失败!!!");
exit(OVERFLOW); // exit(-1)程序异常退出
}
L->next = L; // 头结点指针域指向本身
L->prior = L;
for (int i=0; i<10; i++) { // 生成新结点
DuLinkList p = (DuLinkList)malloc(sizeof(DuLNode));
// scanf("%d", &p->data); // 输入元素值 赋给新生成结点的数据域
p->data = rand()%100;
// 插入到表头
p->next = L->next; // 插入结点 指向 后继
p->prior = L; // 插入结点 反向指向 头结点
L->prior->next = p; // 后继 反向指向 插入结点
L->next = p; // 头结点 指向 插入结点
//printf("%d ", p->data); // 查看是否插入了新的元素
}
}// CreateList_DuL_10
// 逆位序输入(随机产生)n个元素的值,建立带表头结点的线性表L(头插法)。
void CreateList_DuL_Head(DuLinkList &L, int n) {
srand((unsigned)time(NULL)); // 初始化随机数种子
// 先建立一个带头结点的单链表
L = (DuLinkList)malloc(sizeof(DuLNode));
if(!L) {
printf("存储分配失败!!!");
exit(OVERFLOW); // exit(-1)程序异常退出
}
L->next = L; // 头结点指针域指向本身
L->prior = L;
L->data = 5201314;
for (int i=n; i>0; --i) {
DuLinkList p = (DuLinkList)malloc(sizeof(DuLNode));// 生成新结点
// scanf("%d", &p->data); // 输入元素值
// 随机生成100以内的数字
p->data = rand()%100; // 将生成的元素值赋给新生成结点的数据域
// p->data = i; // 将生成的元素值赋给新生成结点的数据域
// 插入到表头
p->next = L->next; // 插入结点 指向 第一个结点
L->next->prior = p; // 第一个结点 反向指向 插入结点
p->prior = L; // 插入结点 反向指向 头结点
L->next = p; // 头结点 指向 插入结点
}
}// CreateList_DuL 算法2.11更改
// 顺位序输入(随机产生)n个元素的值,建立带表头结点的线性表L(尾插法)。
void CreateList_DuL_Tail(DuLinkList &L, int n) {
srand((unsigned)time(NULL)); // 初始化随机数种子
// 先建立一个带头结点的单链表
L = (DuLinkList)malloc(sizeof(DuLNode));
if(!L) {
printf("存储分配失败!!!");
exit(OVERFLOW); // exit(-1)程序异常退出
}
L->next = L; // 头结点指针域指向本身
L->prior = L;
for (int i=0; i<n; ++i) {
DuLinkList p = (DuLinkList)malloc(sizeof(DuLNode));
// scanf("%d", &p->data); // 输入元素值
// 随机生成100以内的数字
p->data = rand()%100; // 将生成的元素值赋给新生成结点的数据域
// 插入到表尾
p->prior = L->prior; // 插入结点 反向指向 表尾结点
L->prior->next = p; // 表尾结点 指向 插入结点
p->next = L; // 插入结点 指向 头结点
L->prior = p; // 头结点 反向指向 插入结点
}
}
// 初始化菜单
void initMenu() {
printf("\n\t\t*****************************************\n");
printf("\n\t\t\t\t 循环双向链表\n");
printf("\n\t\t 1.创建随机表\t\t 2.构造空线性表\n\t\t 3.销毁线性表\t\t 4.清空线性表\n\t\t 5.线性表是否为空\t 6.线性表的长度");
printf("\n\t\t 7.查找表中元素\t 8.插入新元素\n\t\t 9.删除某个元素\t 10.遍历线性表\n\t\t 11.回到主菜单\t\t 0.退出");
}
// 回到主菜单
void mainMenu() {
printf("\n\t\t*****************************************\n");
printf("\n\t\t\t\t 循环双向链表\n");
printf("\n\t\t 1.创建随机表\t\t 2.构造空线性表\n\t\t 3.销毁线性表\t\t 4.清空线性表\n\t\t 5.线性表是否为空\t 6.线性表的长度");
printf("\n\t\t 7.查找表中元素\t 8.插入新元素\n\t\t 9.删除某个元素\t 10.遍历线性表\n\t\t 11.回到主菜单\t\t 0.退出");
}
int main() {
DuLinkList L = NULL;
initMenu();
int select = -1;
while(select != 0)
{
printf("\n\n请选择你的操作:");
scanf("%d", &select);
switch(select)
{
case 1:// 创建随机表
{
int nCreateOption = -1;
while(nCreateOption!=0 && nCreateOption!=11)
{
printf("\n1.头插法 2.尾插法 3.10个元素的随机表 11.回到主菜单 0.退出查找\n请选择你的操作:");
scanf("%d", &nCreateOption);
switch(nCreateOption)
{
case 1:// 1.头插法
{
printf("请输入要创建的随机表元素个数:");
int nElem;
scanf("%d", &nElem);
CreateList_DuL_Head(L, nElem);
printf("头插法创建随机链表:");
ListTraverse_DuL(L, visit);
}
break;
case 2:// 2.尾插法
{
printf("请输入要创建的随机表元素个数:");
int nElem;
scanf("%d", &nElem);
CreateList_DuL_Tail(L, nElem);
printf("尾插法创建随机链表:");
ListTraverse_DuL(L, visit);
}
break;
case 3:// 3.10个元素的随机表
CreateList_DuL_10(L);
printf("10个元素的随机表:");
ListTraverse_DuL(L, visit);
break;
case 11:// 11.回到主菜单
mainMenu();
break;
case 0:// 0.退出查找
break;
default:
printf("请输入正确的数字!!!\n");
break;
}
}
}
break;
case 2:// 构造空线性表
printf("构造一个空的线性表L。");
InitList_DuL(L);
break;
case 3:// 销毁线性表
printf("销毁线性表L。");
DestroyList_DuL(L);
break;
case 4:// 清空线性表
printf("将L重置为空表。");
ClearList_DuL(L);
break;
case 5:// 线性表是否为空
ListEmpty_DuL(L);
break;
case 6:// 线性表的长度
{
int lLength = ListLength_DuL(L);
if(lLength != -1) printf("线性表的长度为: %d ", lLength);
}
break;
case 7:// 查找表中元素
{
int nSearchOption = -1;
while(nSearchOption!=0 && nSearchOption!=11)
{
printf("1.按位置查找\t 2.按元素查找\t 11.回到主菜单\t 0.退出查找\n请选择你的操作:");
scanf("%d", &nSearchOption);
switch(nSearchOption)
{
case 1:// 1.按位置查找
{
int pos;
ElemType e;
printf("请输入要查找的位置:");
scanf("%d", &pos);
int ret = GetElem_DuL(L, pos, e);
if (ret == -1) {
printf("\n");
break;
} else if (ret == 0) {
printf("查找位置不正确!\n");
break;
}
printf("第%d个元素的值为:%d ", pos, e);
ElemType pre_e, next_e;
if(PriorElem_DuL(L, e, pre_e))
printf("前一个元素为:%d ", pre_e);
if(NextElem_Sq(L, e, next_e))
printf("后一个元素为:%d", next_e);
printf("\n");
}
break;// 2.按元素查找
case 2:
{
printf("请输入要查找的元素:");
ElemType e;
scanf("%d", &e);
int pos = LocateElem_DuL(L, e, compare);
if (pos == -1) {
printf("\n");
break;
} else if (pos == 0) {
printf("没有值为%d的元素。\n", e);
break;
}
printf("值为%d是表中的第%d个元素。\n", e, pos);
}
break;
case 11:// 11.回到主菜单
mainMenu();
break;
case 0:// 0.退出查找
break;
default:
printf("请输入正确的数字!!!\n");
break;
}
}
}
break;
case 8:// 插入新元素
{
ElemType e;
int pos;
int nInsertOption = -1;
while(nInsertOption)
{
printf("请输入要插入的元素位置和元素的值:");
scanf("%d %d", &pos, &e);
int ret = ListInsert_DuL(L, pos, e);
// 线性表未初始化,中断循环,回到主界面
if(ret == -1)
break;
// 插入位置不合法,结束本次循环,继续下次循环
else if(!ret)
{
printf("\n");
continue;
}
// 插入元素
printf("\n现在线性表为:");
ListTraverse_DuL(L, visit);
printf("\n1.是 0.否 是否继续: ");
scanf("%d", &nInsertOption);
}
}
break;
case 9:// 删除某个元素
{
int nDeleteOption = -1;
while(nDeleteOption!=0 && nDeleteOption!=11)
{
printf("1.按位置删除\t 2.按元素删除\t 11.回到主菜单\t 0.退出删除\n请选择你的操作:");
scanf("%d", &nDeleteOption);
switch(nDeleteOption)
{
case 1: // 1.按位置删除
{
ElemType e;
int pos;
printf("请输入要删除的位置:");
scanf("%d", &pos);
int ret = ListDelete_DuL(L, pos, e);
if (ret == -1) {
printf("\n");
break;
} else if (ret == 0) {
printf("删除位置不正确!\n");
break;
}
printf("现在线性表为:");
ListTraverse_DuL(L, visit);
printf("\n");
}
break;
case 2: // 2.按元素删除
{
printf("请输入要删除的元素:");
ElemType e;
scanf("%d", &e);
// 删除的将是第一个出现的元素
int pos = LocateElem_DuL(L, e, compare);
if (pos == -1) {
printf("\n");
break;
} else if (pos == 0) {
printf("没有值为%d的元素。", e);
break;
}
printf("值为%d是表中的第%d个元素。", e, pos);
ListDelete_DuL(L, pos, e);
printf("\n现在线性表为:");
ListTraverse_DuL(L, visit);
printf("\n");
}
break;
case 11:// 11.回到主菜单
mainMenu();
break;
case 0:// 0.退出查找
break;
default:
printf("请输入正确的数字!!!\n");
break;
}
}
}
break;
case 10:// 遍历线性表
printf("遍历线性表:");
ListTraverse_DuL(L, visit);
break;
case 11:// 回到主菜单
mainMenu();
break;
case 0:// 退出
break;
default:
printf("请输入正确的数字!!!");
break;
}
}
return 0;
}
《数据结构》(C语言版)——双向链表
最新推荐文章于 2024-08-20 17:16:26 发布