2021-03-11线性表和链表

数据结构与算法前三章知识练习

包含线性表和链表

#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;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值