笔记:一般线性表

一、顺序表

顺序存储,通过静态或动态开辟[数组]存储数据,可分为静态顺序表和动态顺序表
在这里插入图片描述

静态顺序表 SqList

1. 类型定义

#define MaxSize 10
typedef struct 
{
	ElemType data[MaxSize];  //静态数组 存放元素类型为ElemType,使用完自动回收
	int length;              //当前静态数组中元素个数,即表长
}SqList;

2. 初始化

bool InitList(SqList &L)    
{
	int i = 0;
	for(i = 0; i<MaxSize; i++)     //数组元素设置为0
		L.data[i] = 0;
	L.length = 0;				   //表长设置为0
    return true;
}

3. 判空

bool Empty(SqList L)
{
    return (L.length == 0);
}

4. 插入元素

bool ListInsert(SqList &L, int i, ElemType e)  //插入到表的第i位,即data[i-1]
{
	if(i<1|| i>L.length+1|| L.length==MaxSize) //非法输入或表满
		return false;
	int j = 0;
	for(j = L.length; j>=i; j--)
		L.data[j] = L.data[j-1]; //从后至前, 将data[i-1]及之后元素后移
	L.data[i-1] = e;             //插入
	L.length++;                  //表长+1
    return true;
}

5. 删除元素

bool ListDelete(SqList &L, int i, ElemType &e) //找到表的第i位,即data[i-1],返回至e并从表中删除
{
	if(i<1|| i>L.length)                     //非法输入
		return false;
	e = L.data[i-1];					     //导出data[i-1]至e
	int j = 0;
	for(j = i; j<=L.length - 1; j++)         //从前至后,将data[i]及之后元素前移
		L.data[j-1] = L.data[j]
	L.length--;                              //表长-1
    return true;
}

6. 定位元素位序

int LocateElem(SqList L,ElemType e)
{
	int i = 0;
	for(i = 0; i<L.length ;i++)
		if(L.data[i] == e)  
			return i + 1;   //找到data[i],位置为第i+1个元素
	return 0;	            //查找失败
}

注:顺序表的LocateElem返回的是第一次出现元素e的位序,链表的LocateElem返回的是第一次出现元素e的结点的指针

7. 获取位序元素

ElemType GetElem(SqList L,int i)
{
	assert(i<1|| i>L.length)  ;                   //非法输入
	return L.data[i-1];
}

注:顺序表的GetElem返回的是位序i的元素值,链表的GetElem返回的是第i结点的指针

动态顺序表 SeqList

1. 类型定义

#define InitSize 10  //第一次动态开辟的Elemtype数量
typedef struct  
{
	ElemType* data;			//动态数组 存放元素类型为ElemType
	int length;             //当前动态数组中元素个数,即表长
	int MaxSize;            //当前动态数组中元素的最多个数,即最大表长
}SeqList;

2. 初始化

bool InitList(SeqList &L)
{
	L.data = (ElemType*)malloc(InitSize*sizeof(Elemtype))  //在L.data动态开辟InitSize个Elemtype的大小
	if(L.data == NULL)
		return false;
	L.length = 0;                //表长设置为0
	L.MaxSize = InitSize;        //最大表长设置为InitSize
    return true;
}

3. 扩大空间

bool IncreaseSize(SeqList &L, int len) //扩充len个空间
{
	ElemType* p = (ElemType*)realloc(L.data, (L.MaxSize + len)*sizeof(ElemType)); 
 //在临时指针p动态开辟(当前最大表长+len)个Elemtype的大小,并将L.data数据导入
	if(p == NULL)
		return false;
	L.data = p;            //p的地址给L.data
	L.MaxSize += len;      //最大表长扩大len
    return true;
}

4. 插入元素

bool ListInsert(SeqList &L, int i, ElemType e)  //插入到表的第i位,即data[i-1]
{
	if(i<1|| i>L.length+1|| L.length==L.MaxSize) //非法输入或表满
		return false;
	int j = 0;
	for(j = L.length, j>=i, j--)
		L.data[j] = L.data[j-1]; //从后至前, 将data[i-1]及之后元素后移
	L.data[i-1] = e;             //插入
	L.length++;                  //表长+1
    return true;
}

二、链表

建立结点,每个结点除了存放数据之外,还存放指向其他结点的指针.

单链表 LinkList

在这里插入图片描述在这里插入图片描述

1. 类型定义

typedef struct LNode
{
	ElemType data;   //数据域
	struct LNode* next;  //指针域,指向下一个节点
}LNode,*LinkList; //LinkList用来强调单链表,LNode强调结点

LinkList L; L为未被赋值的LNode型的指针,类似于初始化函数,L指针保存的地址初始化为指向开辟的LNode空间的地址,即指针本身发生了变化,所以要&,类似于修改链表节点值的函数,只修改了L指向的LNode里的data和next值,不改变L本身,所以不用&.

2. 初始化

//不带头结点
bool InitList(LinkList &L)
{
	L = NULL;    //防止脏数据
	return true;
}
//带头结点
bool InitList(LinkList &L) 
{
	L = (LNode*)malloc(sizeof(LNode));
	if(L == NULL)
		return false;
	L->next = NULL;
	return true;
}

3. 判空

//不带头结点
bool Empty(LinkList L)
{
	return (L == NULL);
}
//带头结点
bool Empty(LinkList L)
{
	return (L->next == NULL);
}

4. 求表长

//无头结点
int Length(LinkList L)
{
	if(Empty(L))
		return 0;         //空表为0
	int length = 1;
	Node* p = L;          //从第一个结点出发
	while(p->next != NULL)
	{
		p = p->next;
		length++;
	}
	return length;
}
//有头结点
int Length(LinkList L)
{
	if(Empty(L))
		return 0;
	int length = 1;
	Node* p = L->next;
	while(p->next != NULL)
	{
		p = p->next;
		length++;
	}
	return length;
}

5. 给定元素获取指针

//不带头结点
LNode* LocateElem(LinkList L,ElemType e)
{
	LNode* p = L;  //从第一个结点开始找
	while(p!= NULL && p->data!=e)  //直到找到e元素
		p = p->next;
	return p;   //找到后返回该结点指针 找不到返回NULL
}
//带头结点
LNode* LocateElem(LinkList L,ElemType e)
{
	LNode* p = L->next;  
	while(p!= NULL && p->data!=e)  
		p = p->next;
	return p;   
}

注:都要从第一个存储数值的结点开始匹配e的值

6. 给定位序获取指针

//不带头结点
LNode* GetElem(LinkList L,int i)
{
	if(i<1)
		return NULL;   //非法输入
	LNode* p = L;      //从第一个结点开始
	int j = 1;
	while(p != NULL && j<i) 
	{
		p = p->next;
		j++;
	}
	return p ; //返回i结点指针,若i大于表长则返回NULL
}
//带头结点
LNode* GetElem(LinkList L,int i)
{
    if(i == 0)
        return L;      //返回头结点
	if(i<1)
		return NULL;   //非法输入
	LNode* p = L->next;      //从第一个结点开始
	int j = 1;
	while(p != NULL && j<i) 
	{
		p = p->next;
		j++;
	}
	return p ; //返回i结点指针,若i大于表长则返回NULL
}

7. 指定结点后插

bool InsertNextNode(LNode* p,ElemType e)
{
	if(p == NULL)
	    return false;  
	LNode* s=(LNode*)malloc(sizeof(LNode)); //s指向新插入的结点
	if(s == NULL)
		return false;  //内存分配失败
	s->data = e;       //新结点赋值
	s->next = p->next; //新结点指向原p之后的结点
	p->next = s;       //p指向新结点 
	return true;
}

8. 指定结点前插

原理:指定结点后插之后,交换两结点的data数据

bool InsertPriorNode(LNode* p,ElemType e)
{
	if(InsertNextNode(p,e))
	{
		ElemType temp = p->data;
		p->data = p->next->data;
		p->next->data = temp;
		return true;
	}
	else 
		return false;
}

9. 指定位序插入

原理:利用GetElem找到i-1结点的指针,对i-1结点进行后插操作

//不带头结点
bool ListInsert(LinkList &L, int i ,ElemType e)
{
	if(i<1)
		return false;   //非法输入,i过小
	if(i == 1)          //第一个结点
	{
		LNode* s=(LNode*)malloc(sizeof(LNode));//s指向新插入的结点
		s->data = e;       //新结点赋值
		s->next = L;	   //新结点的next指针指向原来的首结点
		L = s;             //改变指向第一个结点的指针L
	}
	LNode* p = GetElem(L,i-1); //p指向i-1结点
	return InsertNextNode(p,e)
 //如果return false,可能由于非法输入,i大于表长+1导致GetElem返回NULL 或者内存开辟失败
}
//带头结点
bool ListInsert(LinkList &L, int i ,ElemType e)
{
	if(i<1)
		return false;   //非法输入,i过小
	LNode* p = GetElem(L,i-1); //p指向i-1结点
	return InsertNextNode(p,e)
}

注:无头结点需要对i=1进行特殊处理,因此大多数情况都建立带头结点链表

10. 指定结点删除

原理:将后续结点的数据域和指针域转移给其本身,然后释放后续结点

bool DeleteNode(LNode* p, ElemType &e)
{
	if(p == NULL || p->next == NULL) 
//p指向尾结点时方法不可用,需遍历至next指向p的结点,另其next指针指向NULL,并释放原后续结点p
		return false;
    e = p->data;
	LNode* q = p->next;  //q指向p后续结点
	p->data = q->data;        //转移数据域
	p->next = q->next;        //转移指针域
	free(q);
	return true;
}

11. 指定位序删除

原理:利用GetElem找到i-1结点的指针,进行后续操作

//不带头结点
bool ListDelete(LinkList &L, int i, Elemtype &e)
{
	if(i == 1)
	{
		Node* p = L;
		e = p->data;
		L = L->next;
		free(p);
	}
	Node* p = GetElem(L,i-1); //p指向i-1结点
	if(p == NULL || p->next == NULL)//i-1 结点为空或i-1结点无后续结点
		return false; 
	LNode* q = p->next; //q指向i结点,即待删除结点
	e = q->data;
	p->next = q->next;
	free(q);
	return true;
}
//带头结点
bool ListDelete(LinkList &L, int i, Elemtype &e)
{
	Node* p = GetElem(L,i-1);
	if(p == NULL || p->next == NULL)
		return false; 
	LNode* q = p->next; 
	e = q->data;
	p->next = q->next;
	free(q);
	return true;
}

12. 头插法建立单链表

对传入的已被初始化的链表头指针L进行逆向建表

LinkList List_HeadInsert(LinkList &L)
{
	Elemtype x;
	LNode* s;
	scanf("",&x);
	while(x!=9999)
	{
		s = (LNode*)malloc(sizeof(Node));
		s->data = x;
		s->next = L->next; 
		L->next = s;
		scanf("",&x);
	}
	return L;
}

13 .尾插法建立单链表

对传入的已被初始化的链表头指针L进行正向建表

LinkList List_TailInsert(LinkList &L)
{
	ElemType x;
	LNode* r = L;//尾指针
	LNode* s ;   //s指向新结点
	scanf("",&x);
	while(x!=9999)
	{
		s = (LNode*)malloc(sizeof(LNode));
		s->data = x;  
		s->next = NULL;
		r->next = s;  //当前尾结点指向新结点
		r = s;        //尾指针指向新结点
		scanf("",&x);
	}
	return L;
}

双链表 DLinkList

在这里插入图片描述

1.类型声明

typedef struct DNode
{
	ElemType data;
	struct DNode* prior;
	struct DNode* next;
}DNode,*DLinkList;

2.初始化

bool InitList(DLinkList &L)
{
	L = (DNode*)malloc(sizeof(DNode));
	if(L == NULL)
		return false;
    L->prior = NULL;
	L->next = NULL;
	return true;
}

3.指定结点后插

在这里插入图片描述

bool InsertNextNode(DNode* p,ElemType e)
{
	if(p == NULL)
	    return false;   
	DNode* s=(DNode*)malloc(sizeof(DNode)); //s指向新插入的结点
	if(s == NULL)
		return false; 
	s->data = e;       
	s->next = p->next; 
	if(p->next != NULL)   // p如果没有后续结点
		p->next->prior = s;       //p的下一个结点的前指针指向新结点 
	s->prior = p;
	p->next = s;
	return true;
}

4.指定结点删除

bool DeleteNode(DNode* p, ElemType &e)
{
	if(p == NULL || p->next == NULL) 
		return false;
    e = p->data;
	p->prior->next = p->next;
    p->next->prior = p->prior;
	free(p);
	return true;
}

循环链表 CLinkList

1.单循环链表

在这里插入图片描述
类型定义与单链表相同

初始化时需要 L->next = L;

判空条件 L->next == L

2.双循环链表

在这里插入图片描述
类型定义与双链表相同

初始化时需要 L->prior = L; L->next = L;

判空条件 L->next == L

静态链表 SLinkList

在这里插入图片描述

1. 类型定义

#define MaxSize 10
typedef struct
{
    ElemType data;
    int next;
}SlinkList[MaxSize];

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值