线性表、栈、队列

参考:https://blog.csdn.net/qq_35644234/category_6521704.html
浙大《数据结构》

数据结构:

第一章 绪论

什么是数据结构?

  • 解决问题方法的效率,跟数据的组织方式有关
  • 解决问题方法的效率,跟空间的利用效率有关
  • 解决问题方法的效率,跟算法的巧妙程度有关

什么是算法?

  • 一个有限指令集
  • 接受一些输入(有的情况不需要输入)
  • 产生输出
  • 一定在有限步骤后终止
  • 每一条指令必须:
    • 有充分明确的目标,不可以有歧义
    • 计算机能处理的范围之内
    • 描述应不依赖于任何一种计算机语言以及具体的实现手段

什么是好的算法?

空间复杂度S(n)——根据算法写成的程序在执行时占用存储单元的长度。

  • 这个长度往往与输入数据的规模有关。
  • 空间复杂度过高的算法可能导致使用的内存超限,造成程序非正常中断。

时间复杂度T(n)——根据算法写成的程序在执行时耗费的时间的长度。

  • 这个长度往往也与输入数据的规模有关。
  • 时间复杂度过高的低效算法可能导致我们在有生之年都等不到运行结果

在分析一般算法的效率时,我们经常关注下面两种复杂度:

  • 最坏情况复杂度Tworst(n)
  • 平均复杂度Tavg(n)
  • Tavg(n) <= Tworst(n)

复杂度分析小窍门

  • 若两段算法分别有复杂度T1(n) = O(f1(n)) 和 T2(n) = O(f2(n)),则

    • T1(n) + T2(n) = max( O(f1(n)), O(f2(n)) )
    • T1(n) * T2(n) = O( f1(n) * f2(n) )
  • 若T(n)是关于n的k阶多项式,那么T(n) = O(n^k) // 这里的O中间有一圆点

  • 一个for循环的时间复杂度等于循环次数乘以循环体代码的复杂度

  • if-else结构的复杂度取决于if的条件判断复杂度和两个分支部分的复杂度,总体复杂度取三者中最大

第二章 线性表

引:多项式表示——链表结构存储非零项

链表中每个结点存储多项式中的一个非零项,包括系数和指数两个数据域以及一个指针域

typedef struct PolyNode *Polynomial;
struct PloyNode {
    int coef;
    int expon;
    Polynomial link;
}

什么是线性表?

线性表(Linear List):由同类型数据元素构成有序序列的线性结构

  • 表中元素个数称为线性表的 长度
  • 线性表没有元素时,称为 空表
  • 表起始位置称为 表头,表结束位置称为 表尾

线性表的顺序存储实现

利用数组的 连续存储空间顺序存放 线性表的各元素

主要操作的实现:

#include <iostream>

using namespace std;

// 扩充容量的步伐
#define sizestep 10
// 开始的容量大小
#define startsize 100

typedef int ElemType;
struct List {
	ElemType* data;	// 数据
	int length;		// 长度
	int size;		// 初始容量
};

// 创建一个空的线性表
void InitList(List& newList)
{
	newList.size = startsize;	// 初始容量为startsize;
	newList.data = new ElemType[newList.size];	// 开辟空间
	newList.length = 0;			// 空表长度为0
}

// 销毁线性表
void DestroyList(List& newList)
{
	newList.length = 0;
	// 一定要先释放堆内存
	delete[] newList.data;
	// 释放堆内存后,并将对应的指针赋予nullptr是个良好的习惯
	newList.data = nullptr;
}

// 清空线性表
void ClearList(List& newList)
{
	newList.length = 0;
	delete[] newList.data;
	newList.data = nullptr;
	// 重新为存放元素的变量开辟一个新的堆内存
	newList.data = new ElemType[newList.size];
}

// 判断线性表是否为空
bool ListEmpty(List newList)
{
	return newList.length;
}

// 返回线性表的长度
int ListLength(List newList)
{
	return newList.length;
}

// 获取线性表上某个位置上的元素的值(位置从1开始计算)
void GetElem(List newList, int i, ElemType& e)
{
	if (ListEmpty(newList)) {
		cout << "线性表为空" << endl;
		return;
	}
	if (i < 1 || i > newList.length) {
		cout << "当前位置超出线性表范围" << endl;
		return;
	}
	e = newList.data[i - 1];
}

// 获取元素的位置(这里直接返回该元素下标,而不是从1开始)
int LocationElem(List newList, ElemType e)
{
	for (int i = 0; i < newList.length; ++i) {
		if (newList.data[i] == e)
			return i;
	}
	return -1;
}

// 获取前驱元素
void PriorElem(List newList, ElemType cur_e, ElemType& pre_e)
{
	int location = 0;
	location = LocationElem(newList, cur_e);
	// 如果location为 -1,说明cur_e不在线性表中
	if (location == -1) {
		cout << cur_e << "不在线性表中" << endl;
		return;
	}
	// 如果location为 0,说明cur_e在线性表的第一个位置,没有前一个元素
	if (location == 0) {
		cout << cur_e << "是线性表的第一个元素,没有前驱" << endl;
		return;
	}
	pre_e = newList.data[location - 1];
}

// 获取后驱元素
void NextElem(List newList, ElemType cur_e, ElemType& next_e)
{
	int location = 0;
	location = LocationElem(newList, cur_e);
	// 如果location为 -1,说明cur_e不在线性表中
	if (location == -1) {
		cout << cur_e << "不在线性表中" << endl;
		return;
	}
	// 如果location为 newList.length - 1,说明cur_e在线性表的最后一个位置,没有后一个元素
	if (location == newList.length - 1) {
		cout << cur_e << "是线性表的最后一个元素,没有后驱" << endl;
		return;
	}
	next_e = newList.data[location + 1];
}

// 向线性表中插入一个元素,需要判断插入位置的合法性(从1开始)
void InsertList(List& newList, int i, ElemType e)
{
	// 插入位置不合法
	if (i < 1 || i > newList.length + 1) {
		cout << "请检查插入位置是否正确" << endl;
		return;
	}
	int j = 0;
	// 如果达到了线性表的最大容量,需要重新为线性表分配新的内存
	if (newList.length == newList.size) {
		// 先保存之前的内容
		ElemType* p = new ElemType[newList.length];
		for (j = 0; j < newList.length; ++j) {
			p[j] = newList.data[j];
		}
		// 扩大容量
		newList.size += sizestep;
		delete[] newList.data;
		// 重新分配内存
		newList.data = new ElemType[newList.size];
		// 恢复之前内容
		for (j = 0; j < newList.length; ++j) {
			newList.data[j] = p[j];
		}
	}

	// 插入内容
	for (int k = newList.length; k > i - 1; --k) {
		newList.data[k] = newList.data[k - 1];
	}
	newList.data[i - 1] = e;
	++newList.length;
}

// 删除一个元素(从1开始算起)
void DeleteList(List& newList, int i)
{
	// 删除位置不合法
	if (i < 1 || i > newList.length) {
		cout << "请检查删除位置是否合法" << endl;
		return;
	}
	for (int j = i - 1; j < newList.length; ++j) {
		newList.data[j] = newList.data[j + 1];
	}
	--newList.length;
}

// 按照元素的值,删除对应元素的内容
// 通过传入参数,来决定删除第一个还是所有
// 0——删除第一个,1——删除所有
void Delete_dataList(List& newList, ElemType e, int order)
{
	int flag = 0;
	for (int i = 0; i < newList.length; ++i) {
		if (newList.data[i] == e) {
			flag = 1;
			// 删除对应位置上的元素,而且i也要减少一个
			DeleteList(newList, i + 1);
			--i;
			if (order == 0)
				return;
		}
	}
	if (flag == 1)
		return;
	cout << e << "不在线性表中" << endl;
}

// 链接两个线性表(当我们进行链接的时候,最好是希望两个链表有序)
void Connece_two_List(List a, List b, List& c)
{
	// 对c进行一些数据初始化
	c.length = c.size = a.length + b.length;
	c.data = new ElemType[c.size];

	// 采用指针的方式进行数据的移动,先把a和b数据第一个和最后一个元素的位置找出来
	int i = 0;
	int j = 0;
	int k = 0;

	while (i <= a.length - 1 && j <= b.length - 1) {
		if (a.data[i] < b.data[j]) {
			c.data[k++] = a.data[i++];
		}
		else if (a.data[i] > b.data[j])
			c.data[k++] = b.data[j++];
		else {
			c.data[k++] = b.data[j++];
			--c.length;
		}
	}

	// 处理剩余一方的元素
	while (i <= a.length - 1) {
		c.data[k++] = a.data[i++];
	}
	while (j <= b.length - 1) {
		c.data[k++] = b.data[j++];
	}
}

// Print输入
void print(List& L)
{
	for (int i = 0; i < L.length; ++i) {
		cout << L.data[i] << " ";
	}
	cout << endl;
}

线性表的链式存储实现

不要求逻辑上相邻的两个元素物理上也相邻;通过“链”建立起数据元素之间的逻辑关系。

  • 插入、删除不需要移动数据元素,只需要修改“链”。

主要操作的实现:

#include <iostream>

using namespace std;

typedef int ElemType;
// 保存长度的头结点,加入这个结点可以方便一些基本的操作
struct Node {
	ElemType value;
	Node* next;		// 下一结点地址
};

// 创建一个空链表
void InitList(Node*& head)
{
	head = new Node();
	head->value = 0;
	head->next = nullptr;
}

// 销毁单链表
void DestroyList(Node*& head)
{
	Node* p;
	while (head) {
		p = head;
		head = head->next;
		delete p;
	}
}

// 清空单链表
void ClearList(Node*& head)
{
	Node* p;
	while (head->next) {
		p = head;
		head = head->next;
		delete p;
	}
	head->value = 0;
}

// 判断链表是否为空,为空返回true
bool ListEmpty(Node* head)
{
	return head->value == 0;
}

// 返回链表的长度
bool ListLength(Node* head)
{
	return head->value;
}

// 得到某个位置上的值
bool GetElem(Node* head, int i, ElemType& value)
{
	// 想要得到的那个位置是否合法
	if (i < 1 || i > head->value)
		return false;

	int j = 0;
	Node* newhead = head;
	while (j < i - 1) {
		newhead = newhead->next;
		++j;
	}
	value = newhead->next->value;
	return true;
}

// 根据值得到该结点的地址以及序号
bool LocateElem(Node* head, ElemType value, Node*& address, int& order)
{
	order = 1;
	Node* temp = head->next;
	while (temp && temp->value != value) {
		temp = temp->next;
		++order;
	}
	if (temp) {
		address = temp;
		return true;
	}
	else {
		address = nullptr;
		order = -1;
		return false;
	}
}

// 得到某个元素前面的那个元素的值
bool PriorElem(Node* newhead, ElemType cur_e, ElemType& pre_e)
{
	while (newhead->next) {
		if (newhead->next->value == cur_e) {
			pre_e = newhead->value;
			return true;
		}
		newhead = newhead->next;
	}
	return false;
}

// 得到某个元素的下一个元素
bool NextElem(Node* newhead, ElemType cur_e, ElemType& next_e)
{
	newhead = newhead->next;	// 从首元结点开始
	while (newhead->next) {
		if (newhead->value == cur_e) {
			next_e = newhead->next->value;
			return true;
		}
		newhead = newhead->next;
	}
	return false;
}

// 插入一个元素
bool InsertList(Node*& head, int i, ElemType value)
{
	// 如果插入位置不合法,返回错误提示
	if (i < 1 || i > head->value + 1)
		return false;

	// 得到插入位置的前一个结点
	int j = 0;
	Node* temp = head;
	while (j < i - 1) {
		temp = temp->next;
		++j;
	}

	// s是一个临时结点
	Node* s = new Node();
	s->value = value;
	s->next = temp->next;
	temp->next = s;
	
	++head->value;
	return true;
}

// 根据下标的值进行删除,并返回删除信息
bool DeleteList(Node*& head, int i, ElemType& value)
{	
	// 如果删除位置不合法,返回错误提示
	if (i < 1 || i > head->value)
		return false;

	// 先找到需要删除结点的前一个结点
	int j = 0;
	Node* temp = head;
	while (j < i - 1) {
		temp = temp->next;
		++j;
	}

	//删除结点
	Node* del = temp->next;
	temp->next = del->next;
	value = del->value;
	delete del;
	return true;
}

// 根据值进行删除,根据标志位删除 第一次出现/所有的该值
// flag = 0 删除第一次    flag = 1 删除所有的该值
bool Delete_data_List(Node*& head, ElemType value, int flag)
{
	ElemType save = -1;	// 临时保存要删除的数据

	// 遍历整个线性表删除结点
	int sign = 0;	// 删除成功or失败
	int j = 0;
	Node* temp = head;
	while (temp->next) {
		temp = temp->next;
		++j;

		if (temp->value == value) {
			DeleteList(head, j, save);
			// 删除了一个,当前位置也会往前推一个
			--j;
			sign = 1;	// 删除成功
			if (flag == 0)
				break;
		}
	}
	if (sign == 0)
		return false;
	return true;
}

// 连接两个链表,默认已经排好序
void Connect_two_List(Node* a, Node* b, Node* c)
{
	c->value = a->value + b->value;
	int a_value = a->value;
	int b_value = b->value;

	int i = 1;
	int j = 1;
	int k = 1;
	Node* a_temp = a->next;
	Node* b_temp = b->next;

	while (i <= a_value && j <= b_value) {
		if (a_temp->value < b_temp->value) {
			++i;
			InsertList(c, k, a_temp->value);

			++k;
			a_temp = a_temp->next;
		}
		else if (a_temp->value > b_temp->value) {
			++j;
			InsertList(c, k, b_temp->value);

			++k;
			b_temp = b_temp->next;
		}
		else {
			++j;
			++i;
			InsertList(c, k, a_temp->value);

			--c->value;
			++k;
			a_temp = a_temp->next;
			b_temp = b_temp->next;
		}
	}

	while (i <= a_value) {
		++i;
		InsertList(c, k, a_temp->value);
		++k;
		a_temp = a_temp->next;
	}
	while (j <= b_value) {
		++i;
		InsertList(c, k, b_temp->value);
		++k;
		b_temp = b_temp->next;
	}
}

广义表与多重链表

什么是广义表?

  • 广义表是线性表的推广
  • 对于线性表而言,n个元素都是基本的 单元素
  • 广义表中,这些元素不仅可以是单元素也可以是 另一个广义表
typedef struct GNode* GList;
struct GNode {
    int Tag;	// 标志域:0表示结点是单元素,1表示结点是广义表
    union {		// 子表指针域SubList与单元素数据域Data复用,即共用存储空间
        ElementType Data;
        GList SubList;
    }URegion;
    GList Next;		// 指向后继结点
}

什么是多重链表?

链表中的节点可能同时隶属于多个链

  • 多重链表中结点的 指针域会有多个,如前面的Next和SubList两个指针域
  • 但包含两个指针域的链表并不一定是多重链表,比如 双向链表不是多重链表

多重链表有广泛的用途:如树、图这样相对复杂的数据结构都可以采用多重链表方式实现存储。

第三章 栈

堆栈

具有一定操作约束的线性表

  • 只在一端(栈顶,Top)做 插入、删除
  • 插入数据:入栈(Push)
  • 删除数据:出栈(Pop)
  • 后入先出:Last In First Out(LIFO)

堆栈的顺序存储实现

栈的顺序存储结构通常由一个一维数组和一个记录 栈顶 元素位置的变量组成。

主要操作的实现:

#include <iostream>

using namespace std;

/*
* 暂时没有写扩充容量的功能
* 后期完善时需注意
*/
// 扩充容量的步伐
#define sizestep 10
// 开始的容量大小
#define startsize 100

typedef int ElemType;
struct SeqStack {
	ElemType* data;	// 数据
	int top;		// 用于栈顶指针
	int size;		// 初始容量
};

// 顺序栈初始化,成功返回栈对象指针,失败返回空指针nullptr
void InitSeqStack(SeqStack& s)
{
	s.size = startsize;
	s.data = new ElemType[s.size];
	s.top = -1;

	if (!s.data) {
		cout << "空间不足" << endl;
		exit(-1);
	}
}

// 判断栈是否为空
bool isEmptySeqStack(SeqStack& s)
{
	return (s.top == -1) ? true : false;
}

// 入栈
bool pushSeqStack(SeqStack& s, ElemType e)
{
	if (s.top == s.size - 1) {
		return false;
	}
	s.data[++s.top] = e;
	return true;
}

// 出栈
bool popSeqStack(SeqStack& s, ElemType& e)
{
	if (s.top == -1)	// if (isEmptySeqStack(s))
		return false;
	else {
		e = s.data[s.top--];
		return true;
	}
}

// 取栈顶元素
bool topSeqStack(SeqStack s, ElemType& e)
{
	if (s.top == -1)	
		return false;	// 栈空
	else {
		e = s.data[s.top];
		return true;
	}
}

// 清空栈
void clearSeqStack(SeqStack& s)
{
	s.top = -1;
	delete[] s.data;
	s.data = nullptr;
	// 重新分配堆内存
	s.data = new ElemType[s.size];
}

// 销毁栈
void destroySeqStack(SeqStack& s)
{
	// 归零
	s.size = 0;
	s.top = -1;
	delete[] s.data;
	s.data = nullptr;
}

// 实现两栈共享空间
struct DoubleSeqStack {
	ElemType* data;
	int top1;
	int top2;
};

void initDoubleSeqStack(DoubleSeqStack& s)
{
	s.data = new ElemType[startsize];
	s.top1 = -1;
	s.top2 = startsize;
}

// 入栈,根据flag选择 栈1 还是 栈2
bool pushDoubleSeqStack(DoubleSeqStack& s, ElemType e, int flag)
{
	// 栈满
	if (s.top1 + 1 == s.top2)
		return false;

	if (flag == 1) {
		s.data[++s.top1] = e;
	}
	else if (flag == 2) {
		s.data[--s.top2] = e;
	}
	else {
		cout << "flag有误" << endl;
		return false;
	}
	return true;
}

// 出栈,根据flag选择 栈1 还是 栈2
bool popDoubleSeqStack(DoubleSeqStack& s, ElemType& e, int flag)
{
	if (flag == 1) {
		if (s.top1 == -1)
			return false;
		e = s.data[s.top1--];
	}
	else if (flag == 2) {
		if (s.top2 == startsize)
			return false;
		e = s.data[s.top2++];
	}
	else {
		cout << "flag有误" << endl;
		return false;
	}

	return true;
}

例:用一个数组实现两个堆栈,要求最大地利用数组空间,使数组只要有空间入栈操作就可以成功。

#define startsize 100

typedef int ElemType;
// 实现两栈共享空间
struct DoubleSeqStack {
	ElemType* data;
	int top1;
	int top2;
};

void initDoubleSeqStack(DoubleSeqStack& s)
{
	s.data = new ElemType[startsize];
	s.top1 = -1;
	s.top2 = startsize;
}

// 入栈,根据flag选择 栈1 还是 栈2
bool pushDoubleSeqStack(DoubleSeqStack& s, ElemType e, int flag)
{
	// 栈满
	if (s.top1 + 1 == s.top2)
		return false;

	if (flag == 1) {
		s.data[++s.top1] = e;
	}
	else if (flag == 2) {
		s.data[--s.top2] = e;
	}
	else {
		cout << "flag有误" << endl;
		return false;
	}
	return true;
}

// 出栈,根据flag选择 栈1 还是 栈2
bool popDoubleSeqStack(DoubleSeqStack& s, ElemType& e, int flag)
{
	if (flag == 1) {
		if (s.top1 == -1)
			return false;
		e = s.data[s.top1--];
	}
	else if (flag == 2) {
		if (s.top2 == startsize)
			return false;
		e = s.data[s.top2++];
	}
	else {
		cout << "flag有误" << endl;
		return false;
	}

	return true;
}

堆栈的链式存储实现

栈的链式存储结构实际上就是一个单链表,叫做 链栈。插入和删除操作只能在链栈的栈顶进行。

栈顶指针Top应该在链表的哪一头?

以链表为底层的数据结构时,以链表头为栈顶,便于节点的插入与删除,压栈产生的新节点将一直出现在链表的头部

主要操作的实现:

#include <iostream>

using namespace std;

typedef int ElemType;
// 链栈结点
struct StackNode {
	ElemType value;
	StackNode* next;
};
// 链栈结构
struct LinkStack {
	StackNode* top;
	int length;
};

// 初始化
void initStack(LinkStack& s)
{
	s.top = nullptr;
	s.length = 0;
}

// 判断栈是否为空
bool isEmptyStack(LinkStack s)
{
	return (!s.top) ? true : false;
}

// 入栈
bool pushStack(LinkStack s, ElemType e)
{
	StackNode* temp = new StackNode;
	// 空间申请失败
	if (!temp) {
		return false;
	}

	temp->value = e;
	temp->next = s.top;
	// 将新元素作为栈顶指针
	s.top = temp;
	++s.length;
	return true;
}

// 出栈
bool popStack(LinkStack& s, ElemType& e)
{
	// 空栈
	if (!s.top)
		return false;

	e = s.top->value;
	StackNode* temp = s.top;
	s.top = s.top->next;
	--s.length;
	delete temp;

	return true;
}

// 获取栈顶元素
bool GetTop(LinkStack s, ElemType& e)
{
	if (!s.top)
		return false;
	e = s.top->value;
	return true;
}

例:表达式求值

中缀表达式如何转换为后缀表达式:

从头到尾读取中缀表达式的每个对象,对不同对象按不同的情况处理。

  1. 运算数:直接输出
  2. 左括号:压入堆栈
  3. 右括号:将栈顶的运算符弹出并输出,直到遇到左括号(出栈,不输出)
  4. 运算符:
    • 若优先级大于栈顶运算符时,则把它压栈
    • 若优先级小于栈顶运算符时,将栈顶运算符弹出并输出;再比较新的栈顶运算符,直到该运算符大于栈顶运算符优先级为止,然后将该运算符压栈
  5. 若各对象处理完毕,则把堆栈中存留的运算符一并输出

堆栈的其他引用

  • 函数调用及递归实现
  • 深度优先搜索
  • 回溯算法

第四章 队列

什么是队列?

具有一定操作约束的线性表

  • 插入和删除操作:只能在一端插入,而在另一端删除
  • 数据插入:入队
  • 数据删除:出队
  • 先来先服务
  • 先进先出:FIFO

队列的顺序存储实现

队列的顺序存储结构通常由一个 一维数组 和一个记录队列头元素位置的变量 front以及一个记录队尾元素位置的变量 rear组成。

循环队列

堆栈空和满的判别条件是什么?

解决方案:

  1. 设置一个标志变量flag,当front == rear,且flag = 0时为队列空;当front == rear,且flag = 1时为队列满。
  2. 当队列为空时,条件是front == rear;当队列满时,修改条件,保留一个元素空间front=(rear+1)%MAXSIZE

主要操作的实现:

#include <iostream>

using namespace std;

#define MAXSIZE 100
typedef int ElemType;

struct SeqQueue {
	ElemType* data;
	int front;
	int rear;
};

// 初始化
void initSeqQueue(SeqQueue& Q)
{
	Q.data = new ElemType[MAXSIZE];
	if (!Q.data) {
		exit(-1);
	}
	Q.front = 0;
	Q.rear = 0;
}

// 入队
bool enqueue(SeqQueue& Q, ElemType e)
{
	if ((Q.rear + 1) % MAXSIZE == Q.front) {
		return false;
	}
	Q.data[Q.rear] = e;	// 将e赋值给队尾
	Q.rear = (Q.rear + 1) % MAXSIZE;
	return true;
}

// 出队
bool dequeue(SeqQueue& Q, ElemType& e)
{
	if (Q.front == Q.rear) {
		return false;
	}
	e = Q.data[Q.front];
	Q.front = (Q.front + 1) % MAXSIZE;
	return true;
}

// 求队长
int lengthSeqQueue(SeqQueue Q)
{
	return (Q.rear - Q.front + MAXSIZE) % MAXSIZE;
}

// 取队头元素
bool GetHead(SeqQueue Q, ElemType& e)
{
	if (Q.front == Q.rear) {
		return false;
	}
	else {
		e = Q.data[Q.front];
		return true;
	}
}

队列的链式存储实现

队列的链式存储结构也可以用一个 单链表 实现。插入和删除操作分别在链表的两头进行;队列指针front和rear应该分别指向链表的哪一头?

front 指向链表的头,rear指向链表的尾

注意:下面的队列中有一个头结点

主要操作的实现:

#include <iostream>

using namespace std;

typedef int ElemType;

struct QNode {
	ElemType data;
	QNode* next;
};

struct LinkQueue {
	QNode* front;	// 队头指针
	QNode* rear;	// 队尾指针
};

// 初始化
void initQueue(LinkQueue& Q)
{
	// front和rear指向头结点,头结点不存储元素
	Q.front = Q.rear = new QNode;
	if (!Q.front) {
		exit(-1);
	}
	Q.front->next = nullptr;
}

// 判断队是否为空
bool isEmptyQueue(LinkQueue& Q)
{
	return (!Q.rear->next) ? true : false;
}

// 取队头元素
bool GetHeadQueue(LinkQueue& Q)
{
	if (Q.front == Q.rear) {
		return false;
	}
	else {
		return Q.front->next->data;
	}
}

// 入队
bool enqueue(LinkQueue& Q, ElemType e)
{
	QNode* temp = new QNode;
	if (!temp) {
		return false;
	}
	temp->data = e;
	temp->next = nullptr;
	Q.rear->next = temp;
	Q.rear = temp;
	return true;
}

// 出队
bool dequeue(LinkQueue& Q, ElemType& e)
{
	if (Q.front == Q.rear) {
		return false;
	}
	QNode* temp = Q.front->next;	// 临时指针指向首元结点
	e = temp->data;
	Q.front->next = temp->next;
	if (Q.rear == temp)
		Q.rear = Q.front;
	delete temp;
}

// 销毁队列
void destroyQueue(LinkQueue& Q)
{
	while (Q.front) {
		Q.rear = Q.front->next;
		delete Q.front;
		Q.front = Q.rear;
	}
	Q.rear = Q.front = nullptr;
}

例:多项式的加减法运算实现

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
16进制10进制.txt 32.txt asm.txt Crctable.txt C标志符命名源程序.txt erre.txt erre2.txt ff.txt for循环的.txt list.log N皇后问题回溯算法.txt ping.txt re.txt source.txt winsock2.txt ww.txt 万年历.txt 万年历的算法 .txt 乘方函数桃子猴.txt 乘法矩阵.txt 二分查找1.txt 二分查找2.txt 二叉排序树.txt 二叉树.txt 二叉树实例.txt 二进制数.txt 二进制数2.txt 余弦曲线.txt 余弦直线.txt 傻瓜递归.txt 冒泡排序.txt 冒泡法改进.txt 动态计算网络最长最短路线.txt 十五人排序.txt 单循环链表.txt 单词倒转.txt 单链表.txt 单链表1.txt 单链表2.txt 单链表倒序.txt 单链表的处理全集.txt 双链表正排序.txt 反出字符.txt 叠代整除.txt 各种排序法.txt 哈夫曼算法.txt 哈慢树.txt 四分砝码.txt 四塔1.txt 四塔2.txt 回文.txt 图.txt 圆周率.txt 多位阶乘.txt 多位阶乘2.txt 大加数.txt 大小倍约.txt 大整数.txt 字符串查找.txt 字符编辑.txt 字符编辑技术(插入和删除) .txt 完数.txt 定长串.txt 实例1.txt 实例2.txt 实例3.txt 小写数字转换成大写数字1.txt 小写数字转换成大写数字2.txt 小写数字转换成大写数字3.txt 小字库DIY-.txt 小字库DIY.txt 小孩分糖果.txt 小明买书.txt 小白鼠钻迷宫.txt 带头结点双链循环线性表.txt 平方根.txt 建树和遍历.txt 建立链表1.txt 扫描码.txt 挽救软盘.txt 换位递归.txt 排序法.txt 推箱子.txt 数字移动.txt 数据结构.txt 数据结构2.txt 数据结构3.txt 数组完全单元.txt 数组操作.txt 数组递归退出.txt 数组递归退出2.txt 文件加密.txt 文件复制.txt 文件连接.txt 无向图.txt 时间陷阱.txt 杨辉三角形.txt 单元加.txt 操作.txt 桃子猴.txt 桶排序.txt 检出错误.txt 检测鼠标.txt 汉字字模.txt 汉诺塔.txt 汉诺塔2.txt 灯塔问题.txt 猴子和桃.txt 百鸡百钱.txt 矩阵乘法动态规划.txt 矩阵转换.txt 硬币分法.txt 神经元模型.txt 穷举搜索法.txt 符号图形.txt 简单数据库.txt 简单计算器.txt 简单逆阵.txt 线性顺序存储结构.txt 线索化二叉树.txt 绘制圆.txt 编随机数.txt 网络最短路径Dijkstra算法.txt 自我复制.txt 节点.txt 苹果分法.txt 螺旋数组1.txt 螺旋数组2.txt 试题.txt 诺汉塔画图版.txt 读写文本文件.txt 货郎担分枝限界图形演示.txt 货郎担限界算法.txt 质因子.txt 输出自已.txt 迷宫.txt 迷宫问题.txt 逆波兰计算器.txt 逆矩阵.txt 逆阵.txt 递堆法.txt 递归桃猴.txt 递归车厢.txt 递推.txt 逻辑移动.txt 链串.txt 链.txt 链表十五人排序.txt 链表(递归).txt 链队列.txt 队列.txt 阶乘递归.txt 阿姆斯特朗数.txt 非递归.txt 顺序.txt 顺序表.txt 顺序队列.txt 骑士遍历1.txt 骑士遍历2.txt 骑士遍历回逆.txt 黑白.txt

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ClimberCoding

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值