数据结构与算法前三章知识练习
包含线性表和链表
#include<iostream>
#include<stdio.h>
//函数结果状态代码
#define MAXSIZE 100
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
//#define OVERFLOW -2
//Status 是函数的类型,其值是函数结果状态代码
typedef int Status,Elemtype;
using namespace std;
//顺序表的定义
typedef struct
{
Elemtype* elem;
int length;
}SqList;//sequence list (顺序表)线性表的顺序表达
//1.1 顺序表的初始化
Status InitList(SqList& L) //对线性表改动,加&
{
L.elem = new Elemtype(MAXSIZE);//为线性表分配大小为MAXSIZE,类型为Elemtype的地址
if (!L.elem)
exit(OVERFLOW); //分配内存失败退出;
L.length = 0;//空表的长度为0;
return OK;
}
//1.2 顺序表的取值
//获取表中第i个元素的值
Status GetElem(SqList L, int i, Elemtype& e)//通过e返回第i个点的值;
{
if (i<1 || i>L.length) //判断i是否合法,i不能越界;
return ERROR;
e = L.elem[i - 1];//第i个值在线性表数组中下标为i-1;
}
//1.3 顺序表中的查找
//查找线性表中指定的元素值e,查找线性表中第一个与e相等的元素,
//若查找成功,则返回该元素在表中的位置序号,若找不到则返回error
Status LocateElem(SqList L, Elemtype e)
{
int i;
for (i = 0; i < L.length; i++)
{
if (L.elem[i] == e)//查找时第一次找到便会退出
return i + 1;
}
return 0;//否则返回error,也就是0;
}
//1.4 顺序表的插入
//在表中第i个位置前插入一个新元素e;
Status ListInsert(SqList& L, Elemtype e, int i)
{
if ((i<1) || i>(L.length+1)) //判断i是否合法,i不能越界,最多在1~n+1之前;
return ERROR;
if (L.length == MAXSIZE)//重点(容易忘):数组已满
return ERROR;
for (int j= L.length-1;j>=i-1; j--)
{
L.elem[j+1] = L.elem[j ];
}
L.elem[i - 1] = e;
++L.length;//不在赋值表达式中,也可以用L.length++
return OK;
}
//1.5 顺序表的删除
//删除位置i处的值;
Status ListDelete(SqList& L, int i)
{
if (i<1 || i>L.length)//判断i是否合法,i不能越界;
return ERROR;
for (int j = i; j <= L.length - 1; j++)
L.elem[j - 1] = L.elem[j];
L.length--;
return OK;
}
//1.6 清空线性表
void ClearList(SqList& L)
{
L.length = 0;//元素个数置为0,但是空间还在;
}
//1.7 求线性表的长度
int GetLength(SqList L)
{
return (L.length);
}
//1.8 销毁线性表
void DestroyList(SqList& L)
{
if (L.elem)
delete L.elem;
}
//1.9 判断线性表L是否为空
int EmptyList(SqList L)
{
if (L.length == 0)
return 1;
else
return 0;
}
//以下为链表的表达形式
//链表的定义
typedef struct Lnode
{
Elemtype data;//结点的数据域
struct Lnode* next;结点的指针域
}Lnode,*LinkList; //LinkList为指向结构体的指针类型
//2.1 单链表的初始化
Status InitList(LinkList& L)
{
L = new Lnode; //生成新结点作为头结点,用头指针L指向头结点
L->next = NULL;//头结点的指针域置空;
return OK;
}
//2.2 单链表的取值
//算法思路:(1)用指针p指着首元结点,用j作为计数器赋初值为1;
// (2)从首元结点开始往下访问,只要当前指向的结点指针P不为空,
// 并且还没达到序号i所在的结点,则继续循环:
// 1.P指向下一结点 2.计数器加1
Status GetRlem(LinkList L, Elemtype& e, int i)
{
Lnode* p;
p = L->next;//此时P指向的是首元结点,即第一个结点
int j = 1;
while (p && (j < i))//扫描,直到p为指向第i个元素或者P为空
{
p = p->next;
j++;
}
if (!p || j > i) return ERROR;//第i个元素不存在(必须判断循环结束对不对)
e = p->data; //取第i个元素
return OK;
}
//2.3 单链表的查找
//查找链表中值为e的值,找到后返回地址,若查找失败,p的值即为NULL。
Lnode* LocateElem(LinkList L, Elemtype e) //返回值为指针
{
Lnode* p;
p = L->next;//此时P指向的是首元结点,即第一个结点
while (p && (p->data != e))
p = p->next;
if (!p)
return ERROR;
else
return p;
}
//2.4 单链表的插入(从头结点开始)
//将值为e的新结点插入到表的第i个结点的位置上,即插到结点a(i-1)与a(i)之间
//算法步骤:(1)查找结点a(i-1)并由指针p指向该结点;
// (2)生成一个新的结点*s;
// (3)将新结点*s的数据域置为e;
// (4)将新结点*s的指针域指向结点a(i);
// (5)将结点a(i-1)的指针域置为*s;
Status ListInsert(LinkList& L, Elemtype e, int i)
{
Lnode* p,*s;
p = L;//此时P指向的是头结点
int j = 0;
while (p && (j < i-1))//扫描,直到p为指向第i-1个元素或者P为空
{
p = p->next;
j++;
}
if (!p || j > i-1) return ERROR;
s = new Lnode; //开辟新的结点
s->data = e;
s->next = p->next;
p->next = s;
return OK;
}
//2.5 单链表的删除
//删除单链表的第i个结点a(i)
//算法步骤:(1)查找结点a(i-1)并由指针p指向该结点;
// (2)临时保存待删除结点a(i)的地址在q中,以备释放;
// (3)将结点*p的指针域直接指向后面一个结点;
// (4)释放q;
Status ListDelete(LinkList& L, int i)
{
Lnode* p,*q;
p = L;//此时P指向的是首元结点,即第一个结点
int j = 0;
while (p ->next&& (j < i - 1))//扫描,直到p为指向第i个元素,确保是可删除的值。
{
p = p->next;
j++;
}
if (!(p->next) || j > i - 1) return ERROR;
q = p->next;
p->next = q->next;
delete p;
return OK;
}
//2.6 求单链表的表长
int ListLength_L(LinkList L)
{
Lnode* p;
p = L->next;
int i = 0;
while (p)
{
i++;
p = p->next;
}
return i;
}
//2.7 清空链表
//算法思路: 将p指向首元结点,q放在第二个结点处,随后delete第一个结点,再将p指向第二个结点,反复执行。
// 当p为空的时候链表被清空,此时需要将头结点的指针域置为NULL;
Status ClearList(LinkList& L)
{
Lnode* p,*q;
p = L->next;
while (p)
{
q = p->next;
delete p;
p = q;
}
L->next = NULL;
return OK;
}
//2.8 判断链表是否为空
//链表中没有元素,但是头结点和头指针还在,只需要看头结点的指针域是否为空
int ListEmpty(LinkList L)
{
if (L->next == NULL)
return 0;
else
return 1;
}
//2.9 销毁单链表
//头指针和头结点都不在了,直接被释放了
Status DestroyList(LinkList& L)
{
Lnode* p;
while (L)
{
p = L;
L = L->next;
delete p;
}
return OK;
}
//2.10 建立单链表
//算法思路:分为两种,一种是头插法:
// (1)从一个空表开始,重复读入数据
// (2)生成新结点,将读入数据存放到新结点的数据域中
// (3)从最后一个结点开始,依次将各节点插入到链表的前端
//例如:建立链表L(a,b,c,d,e);(反复理解!!!)还是很简单的
void CreatList_H(LinkList& L, int n)
{
L = new Lnode;
L->next = NULL;
Lnode* p;
for (int i = n; i > 0; i--)
{
p = new Lnode;
cin >> p->data;
p->next = L->next; //将新加入的结点的指针域置为空
L->next = p;
}
}
//另一种建立方法是尾插法;
void CreatList_R(LinkList& L, int n)
{
L = new Lnode;
L->next = NULL;
Lnode* r,*p;
r = L;
for (int i = 0; i < n; i++)
{
p = new Lnode;
cin >> p->data;
p->next = NULL;
r = p;
}
}
//循环链表:循环链表中没有空指针,表示为空就是尾指针指向头指针(尚未定义)
//双项链表:双链表的定义
typedef struct DuLnode
{
Elemtype data;
struct DuLnode* prior;
struct DuLnode* next;
}DuLnode,*DuLinkList;
//3.1 双链表的查找:查找第i个元素,找到则返回地址,否则报错。
DuLnode* GetElemP_DuL(DuLinkList L, int i)
{
DuLnode* p;
p = L;
int j = 0;
while((p->next)&&j<=i)
{
p = p->next;
j++;
}
if (!p || j > i)
return ERROR;
else
return p;
}
//3.2 双链表的插入(尽量先连后断)
//在带头结点的双链表中的第i个元素的前面插入元素e;
Status ListInsert_DuL(DuLinkList& L, Elemtype e, int i)
{
DuLnode* p,*s;
p = GetElemP_DuL(L, i);
if (!p) //查找第i个元素;
return ERROR;
s = new DuLnode;
s->data = e;
s->prior = p->prior;
p->prior->next = s;
s->next = p;
p->prior = s;
//以下做法应该也可行
/* p->prior->next = s;
s->prior = p->prior;
p->prior = s;
s->next = p;
*/
return OK;
}
//3.3 双链表的删除
//删除带头结点的双向链表中的第i个元素;
Status ListDelete_DuL(DuLinkList& L, int i)
{
DuLnode* p;
p = GetElemP_DuL(L, i);
if (!p) //查找第i个元素;
return ERROR;
p->prior->next = p->next;
p->next->prior = p->prior;
delete p;
return OK;
}