/* 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 LNode {
ElemType data; // 数据域
struct LNode *next; // 指针域
} LNode, *CircleList;
// 操作结果:构造一个空的线性表L。
Status InitList_CL(CircleList &L) {
if(L != NULL)
{
printf("线性表已存在!!!");
return INFEASIBLE; // 返回-1
}
L = (CircleList)malloc(sizeof(LNode));
if(!L) { // 存储分配失败
printf("初始化失败!!!");
exit(OVERFLOW); // exit(-2)程序异常退出
}
L->next = L; // 先建立一个带头结点的单链表,并使头结点指向本身(即头指针L)
return OK;
}// InitList_CL
// 操作结果:销毁线性表L。
Status DestroyList_CL(CircleList &L) {
if(L == NULL)
{
printf("线性表未初始化。");
return INFEASIBLE;
}
CircleList p = L->next, ptmp; // p指向线性表第一个结点
while(p != L) { // p指向头结点时,循环停止
ptmp = p->next;
free(p); // 释放每个结点的指针域
p = ptmp;
}
L->next = L; // 头结点指针域指向本身
free(L); // 释放头结点
L = NULL;
return OK;
}// DestroyList_CL
// 操作结果:将L重置为空表。
Status ClearList_CL(CircleList &L) {
if(!L)
{
printf("线性表未初始化。");
return INFEASIBLE;
}
if(L->next == L)
{
printf("线性表本已空!!!");
return INFEASIBLE;
}
CircleList p = L->next, ptmp; // p指向线性表第一个结点
while(p != L) { // p指向头结点时,循环停止
ptmp = p->next;
free(p); // 释放每个结点的指针域
p = ptmp;
}
L->next = L; // 头结点指针域指向本身
return OK;
}// ClearList_CL
// 操作结果:若L为空表,返回TRUE,否则返回FALSE
Status ListEmpty_CL(CircleList L) {
if(!L)
{
printf("线性表未初始化。");
return INFEASIBLE; // 返回-1
}
else if(L->next == L)
{
printf("线性表为空。");
return TRUE; // 返回1
}
else
{
printf("线性表非空。");
return FALSE; // 返回0
}
}// ListEmpty_CL
// 操作结果:返回L中数据元素个数。
int ListLength_CL(CircleList L) {
if(!L)
{
printf("线性表未初始化。");
return INFEASIBLE; // 返回-1
}
int nElem = 0;
CircleList p = L->next; // p指向第一个结点
while(p != L) {
nElem ++;
p = p->next;
}
return nElem;
}// ListLength
// 操作结果:用e返回L中第i个数据元素的值。1≤i≤ListLength(L) 。
Status GetElem_CL(CircleList L, int i, ElemType &e) {
if(!L) {
printf("线性表未初始化。");
return INFEASIBLE; // 返回-1
}
CircleList p = L->next; // 初始化,p指向第一个结点(表空时,指向头结点)
int j = 1; // j为计数器
while ( (p->next != L) && j<i ) // 顺指针向后查找,直到p指向第i个元素或p指向头结点
{
p = p->next;
++j;
}
if ( p == L || j<i || i<1 )
{
return ERROR; // 第i个元素不存在
}
e = p->data; // 取第i个元素
return OK;
}// GetElem_CL 算法2.8更改
// 操作结果:返回L中第1个与e满足compare()(数据元素判定函数)的数据元素的位序,若这样的数据元素不存在,则返回值为0。
Status compare(ElemType listElem, ElemType e) {
return listElem == e ? TRUE : FALSE;
}// Compare
int LocateElem_CL(CircleList L, ElemType e, Status (*pfn_compare)(ElemType, ElemType)) {
if(!L) {
printf("线性表未初始化。");
return INFEASIBLE; // 返回-1
}
int pos = 1;
CircleList p = L->next; // p指向链表第1个元素
while(p!=L && !(*pfn_compare)(p->data, e)) {
++ pos;
p = p->next; // 指针后移p->next = L时,循环回到头结点
}
if(!L || pos>ListLength_CL(L))
{
return ERROR; // 返回0
}
return pos;
}// LocateElem_CL
// 操作结果:若cur_e是L的数据元素,则用pre_e返回它的前驱,否则操作失败,pre_e无定义。
Status PriorElem_CL(CircleList L, ElemType cur_e, ElemType &pre_e) {
int i = LocateElem_CL(L, cur_e, compare);
// cur_e为第一个元素,其前驱为最后一个元素
if(i==0 || i==1)
{
GetElem_CL(L, ListLength_CL(L), pre_e);
return OK;
}
GetElem_CL(L, i-1, pre_e);
return OK;
}// PriorElem_CL
// 操作结果:若cur_e是L的数据元素,则用next_e返回它的后继,否则操作失败,pre_e无定义。
Status NextElem_Sq(CircleList L, ElemType cur_e, ElemType &next_e) {
int i = LocateElem_CL(L, cur_e, compare);
// cur_e为最后一个元素,其后继为第一个元素
if(i==0 || i==ListLength_CL(L))
{
GetElem_CL(L, 1, next_e);
return OK;
}
GetElem_CL(L, i+1, next_e);
return OK;
}// NextElem_Sq
// 操作结果:在L中第pos个位置之前插入新的元素e,L的长度加1。1≤pos≤ListLength(L)+1。
Status ListInsert_CL(CircleList &L, int pos, ElemType e) {
if (!L) { // 线性表是否存在
printf("线性表未初始化。");
return INFEASIBLE;
}
CircleList p = L; // 定义一个结构体指针变量p,指向线性表第一个结点(若为空,则指向头结点)。
int j = 0;
while ((p->next != L) && j<pos-1) { // 寻找第i-1个结点,并令p指向其前趋。
p = p->next; // p非空,且j<i-1,说明指针位于线性表内
++j;
}
//pos<1 pos-1>j
if (j<pos-1) { // 插入位置是否合法(第i个结点存在,插入的位置在表内)
printf("插入位置不合法。");
return ERROR;
}
CircleList s = (CircleList) malloc(sizeof(LNode));// 生成新结点
s->data = e; // 将插入的元素值 赋给 新生成结点的数据域
s->next = p->next; // 新结点 指向 下一个结点 (即将结点i-1中指向第i个元素的指针域p->next,赋给新结点的指针域s->next)
p->next = s; // 插入位置上一结点 指向 新结点(即将指向新生成结点的指针s,赋给第i-1个元素的指针域p->next)
printf("插入的位置:%d, 插入的元素:%d", pos, e);
return OK;
}// ListInsert_CL 算法2.9更改
// 操作结果:删除L的第pos个数据元素,并用e返回其值,L的长度减1。1≤pos≤ListLength(L)。
Status ListDelete_CL(CircleList &L, int pos, ElemType &e) {
if (!L) { // 线性表是否存在
printf("线性表未初始化。");
return INFEASIBLE;
}
CircleList p = L; // 定义一个结构体指针变量p,指向线性表起始位置(头结点)L。
int j = 0;
while ((p->next != L) && j<pos-1) { // 寻找第i个结点,并令p指向其前趋。
p = p->next;
++j;
}
if ((p->next == L) || pos<1 || j<pos-1)// 删除位置是否合法(结点存在,删除的位置在表内)
return ERROR;
CircleList q = p->next; // 使q指向i-1结点(将结点i-1中指向结点i的指针域,赋给指针变量q)
p->next = q->next; // 将结点i中指向结点i+1的指针域,赋给结点i-1的指针域
e = q->data; // 要删除结点的数据域,赋给e
free(q); // 释放指针变量q
return OK;
}// ListDelete_CL 算法2.10更改
// 操作结果:依次对L的每个数据元素调用函数visit()。一旦vistit()失败,刚操作失败。
Status visit(ElemType e) {
printf("%d->", e);
return OK;
}
Status ListTraverse_CL(CircleList L, Status (*pfn_visit)(ElemType)) {
if(!L) {
printf("线性表未初始化。");
return ERROR;
}
if(L->next == L) {
printf("线性表为空表。");
return ERROR;
}
CircleList p = L->next; // p指向第一个结点
while(p != L) {
visit(p->data);
p = p->next;
}
return OK;
}// ListTraverse
// 创建随机表,包含10个随机数(头插法)。
void CreateList_CL_10(CircleList &L) {
// 提供随机数种子
srand((unsigned)time(NULL));
// 生成头结点
L = (CircleList)malloc(sizeof(LNode));
if(!L) {
printf("存储分配失败!!!");
exit(OVERFLOW); // exit(-1)程序异常退出
}
L->next = L; // 头结点指针域指向本身
for (int i=0; i<10; i++) { // 生成新结点
CircleList p = (CircleList)malloc(sizeof(LNode));
// scanf("%d", &p->data); // 输入元素值 赋给新生成结点的数据域
p->data = rand()%100;
p->next = L->next; // 插入到表头
L->next = p;
printf("%d ", p->data); // 查看是否插入了新的元素
}
}// CreateList_CL_10
// 逆位序输入(随机产生)n个元素的值,建立带表头结点的线性表L(头插法)。
void CreateList_CL_Head(CircleList &L, int n) {
srand((unsigned)time(NULL)); // 初始化随机数种子
// 先建立一个带头结点的单链表
L = (CircleList)malloc(sizeof(LNode));
if(!L) {
printf("存储分配失败!!!");
exit(OVERFLOW); // exit(-1)程序异常退出
}
L->next = L; // 头结点指针域指向本身
for (int i=n; i>0; --i) {
CircleList p = (CircleList)malloc(sizeof(LNode));// 生成新结点
// scanf("%d", &p->data); // 输入元素值
// 随机生成100以内的数字
p->data = rand()%100; // 将生成的元素值赋给新生成结点的数据域
// 插入到表头
p->next = L->next; // 使新结点的指针域 指向 上一次生成的结点
L->next = p; // 头结点的指针域 指向 新生成的结点(将指向新结点的指针p 赋给 头结点的指针域)
}
}// CreateList_CL 算法2.11更改
// 顺位序输入(随机产生)n个元素的值,建立带表头结点的线性表L(尾插法)。
void CreateList_CL_Tail(CircleList &L, int n) {
srand((unsigned)time(NULL)); // 初始化随机数种子
// 先建立一个带头结点的单链表
L = (CircleList)malloc(sizeof(LNode));
if(!L) {
printf("存储分配失败!!!");
exit(OVERFLOW); // exit(-1)程序异常退出
}
L->next = L; // 头结点指针域指向本身
for (int i=0; i<n; ++i) {
CircleList p = (CircleList)malloc(sizeof(LNode));
// scanf("%d", &p->data); // 输入元素值
p->data = rand()%100; // 随机生成100以内的数字,将生成的元素值赋给新生成结点的数据域
// 插入到表尾
L->next = p; // 上一结点 指向 新生成的结点(将新生成结点的指针域 赋给 上一结点的指针域)
p->next = L; // 将新结点的指针域 指向 头结点
}
}
// 初始化菜单
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() {
CircleList L = NULL;
initMenu();
int select = -1;
while(select != 0)
{
printf("\n\n请选择你的操作:");
scanf("%d", &select);
switch(select)
{
case 1:// 创建随机表
printf("请输入要创建的随机表元素个数:");
int nElem;
scanf("%d", &nElem);
CreateList_CL_Head(L, nElem);
printf("创建随机链表:");
ListTraverse_CL(L, visit);
break;
case 2:// 构造空线性表
printf("构造一个空的线性表L。");
InitList_CL(L);
break;
case 3:// 销毁线性表
printf("销毁线性表L。");
DestroyList_CL(L);
break;
case 4:// 清空线性表
printf("将L重置为空表。");
ClearList_CL(L);
break;
case 5:// 线性表是否为空
ListEmpty_CL(L);
break;
case 6:// 线性表的长度
{
int lLength = ListLength_CL(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_CL(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_CL(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_CL(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_CL(L, pos, e);
// 线性表未初始化,中断循环
if(ret == -1)
break;
// 插入位置不合法,中断循环
else if(!ret)
break;
// 插入元素
printf("\n现在线性表为:");
ListTraverse_CL(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_CL(L, pos, e);
if (ret == -1) {
printf("\n");
break;
} else if (ret == 0) {
printf("删除位置不正确!\n");
break;
}
printf("现在线性表为:");
ListTraverse_CL(L, visit);
printf("\n");
}
break;
case 2: // 2.按元素删除
{
printf("请输入要删除的元素:");
ElemType e;
scanf("%d", &e);
// 删除的将是第一个出现的元素
int pos = LocateElem_CL(L, e, compare);
if (pos == -1) {
printf("\n");
break;
} else if (pos == 0) {
printf("没有值为%d的元素。", e);
break;
}
printf("值为%d是表中的第%d个元素。", e, pos);
ListDelete_CL(L, pos, e);
printf("\n现在线性表为:");
ListTraverse_CL(L, visit);
printf("\n");
}
break;
case 11:// 11.回到主菜单
mainMenu();
break;
case 0:// 0.退出查找
break;
default:
printf("请输入正确的数字!!!\n");
break;
}
}
}
break;
case 10:// 遍历线性表
printf("遍历线性表:");
ListTraverse_CL(L, visit);
break;
case 11:// 回到主菜单
mainMenu();
break;
case 0:// 退出
break;
default:
printf("请输入正确的数字!!!");
break;
}
}
return 0;
}