栈的排序:

本篇内容引发于下图问题,下面将分别给出递归与使用另一个栈的实现。

一、只用一个栈的递归实现栈的排序:

核心函数:

void SqSort(SqStack& s) {
    if (s.top != s.base) {
        int temp;
        Pop(s, temp);  // 移除栈顶元素
        SqSort(s);     // 递归排序剩余的栈
        InsertSortedStack(s, temp);  // 将移除的元素插入排序好的栈中
    }
}

void InsertSortedStack(SqStack& s, int e) {
    if (s.top == s.base || GetTop(s) <= e) {
        Push(s, e);  // 如果栈为空或栈顶小于等于元素,则插入
    } else {
        int temp;
        Pop(s, temp);  // 否则弹出栈顶元素,递归插入
        InsertSortedStack(s, e);
        Push(s, temp);  // 重新将弹出的元素压栈
    }
}

核心思想

  1. 递归移除栈顶元素:不断从栈中弹出元素,直到栈为空(或只有一个元素)。这相当于将问题分解为处理更小的子栈。
  2. 将弹出的元素插入回已排序的栈:当栈变为空时,从递归调用返回,在返回的过程中,将每个弹出的元素插入到已排序的子栈中。这个插入操作需要保证栈中的元素始终保持顺序。

算法步骤

  1. 递归基准情况:如果栈为空或只有一个元素,则直接返回,递归结束。这是递归的停止条件。
  2. 弹出栈顶元素:从栈中移除栈顶元素,将其保存到临时变量中。
  3. 递归调用自身:对剩下的栈(不包括弹出的元素)进行递归排序。递归调用继续,直到栈为空。
  4. 插入栈顶元素:在递归返回时,将刚才弹出的元素插入到已排序的子栈中,确保插入后栈仍然是有序的。
  5. 恢复栈的完整性:通过在递归返回过程中逐步将元素按正确顺序插入,栈最终被排序。

具体步骤实现

  1. 递归函数 SqSort
    • 检查栈是否为空或只有一个元素,如果是,递归结束。
    • 弹出栈顶元素,并递归排序剩余的栈。
    • 递归返回后,调用 InsertSortedStack,将栈顶元素按顺序插回栈。
  2. 辅助函数 InsertSortedStack
    • 检查栈是否为空,或者栈顶元素是否小于等于要插入的元素。如果是,则直接将元素压栈。
    • 否则,弹出栈顶元素,递归调用自身,将元素插入剩余栈中,再将弹出的栈顶元素压栈。

时间复杂度:

  • 时间复杂度:栈中的每个元素都会被弹出并重新插入栈,因此时间复杂度为 O(n^2),其中 n 是栈中的元素个数。
  • 空间复杂度:由于使用递归,每次递归调用都会占用栈空间,空间复杂度为 O(n)。

完整代码及测试:

#include <iostream>
#define MAXSIZE 100
#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int Status;
using namespace std;
typedef struct
{
	int* base;
	int* top;
	int  stacksize;
}SqStack;
Status InitStack(SqStack& S)
{//栈初始化
	S.base = new int[MAXSIZE];
	if (!S.base)
		return ERROR;
	S.top = S.base;
	S.stacksize = MAXSIZE;

	return OK;
}
Status Push(SqStack& S, int e)
{//入栈
	if (S.top - S.base >= S.stacksize)
		return OVERFLOW;
	*S.top++ = e;

	return OK;
}
Status Pop(SqStack& S,int &e)
{//出栈
	if (S.top == S.base)
		return ERROR;
	e=*--S.top;

	return OK;
}
int GetTop(SqStack S)
{//取栈顶元素
	if (S.top == S.base)
		return ERROR;
	return *(S.top - 1);
}

void Out(SqStack s) {
	int* flag = s.top;
	while (flag > s.base) {
		cout << *(flag - 1) << " ";
		flag--;
	}
	cout << endl;
}
// 将元素插入到已排序的栈中的正确位置
void InsertSortedStack(SqStack &s, int e) {
	if (s.top == s.base || GetTop(s) <= e) {
		Push(s, e); // 如果栈为空或栈顶元素小于等于当前元素,则直接入栈
	}
	else {
		int temp = 0;
		Pop(s, temp); // 否则,弹出栈顶元素
		InsertSortedStack(s, e); // 递归调用将元素插入到正确的位置
		Push(s, temp); // 插入完成后,将之前弹出的元素重新压栈
	}
}

// 递归排序栈
void SqSort(SqStack& s) {
	if (s.top != s.base) {
		int temp = 0;
		Pop(s, temp); // 移除栈顶元素
		SqSort(s); // 递归排序剩余的栈
		InsertSortedStack(s, temp); // 将移除的元素插入到已排序的栈中
	}
}


int main()
{
	SqStack s;
	InitStack(s);
	Push(s, 4);
	Push(s, 2);
	Push(s, 6);
	Push(s, 5);
	Push(s, 1);
	Push(s, 3);

	Out(s);

	SqSort(s);
	Out(s);

}

输出:

3 1 5 6 2 4
6 5 4 3 2 1

二、使用另一个栈实现栈的排序:

核心函数

void SqSort(SqStack& s) {
	SqStack ts;//辅助栈
	InitStack(ts);

	while (s.top > s.base) {
		int temp1 = 0;
		Pop(s, temp1);

		//当辅助栈为空或者取出元素小于辅助栈栈顶元素时将temp1入辅助栈
		if (ts.base == ts.top || GetTop(ts) >= temp1) {
			Push(ts, temp1);
		}
		else {//当取出元素大于辅助栈栈顶元素时,将辅助栈内元素放回原栈,直到temp1小于辅助栈栈顶元素
			while (ts.base != ts.top&& GetTop(ts) < temp1){//注意此处的条件
				int temp2 = 0;
				Pop(ts, temp2);
				Push(s, temp2);
			}//由于辅助栈内是排好序的,按顺序取出入原栈,依然有序,放入temp1后这些元素将再次返回辅助栈
			Push(ts, temp1);
		}
	}

	//排序后将辅助栈元素返回到原栈中
	while (ts.base != ts.top) {
		int e;
		Pop(ts, e);
		Push(s, e);
	}

}

核心思想

该排序算法利用辅助栈对主栈中的元素进行排序。通过逐个弹出主栈中的元素,依次与辅助栈的栈顶元素比较,有序地放入辅助栈。当主栈元素较大时直接入辅助栈;当主栈元素较小时,将辅助栈中的较大元素重新放回主栈,直到找到适当位置,再将较小元素放入辅助栈。最后将辅助栈元素放回主栈。

算法步骤

  1. 初始化一个辅助栈 ts
  2. 从主栈 s 逐一弹出元素:
    • 如果辅助栈为空,或当前弹出的元素不大于辅助栈的栈顶元素,则将该元素直接推入辅助栈。
    • 否则,反复将辅助栈中比当前元素大的元素弹出,推回主栈,直到找到合适位置,再将当前元素放入辅助栈。
  3. 重复上述过程,直到主栈中的所有元素都按顺序存入辅助栈。
  4. 最后,将辅助栈中的元素依次弹出,重新放回主栈,使得主栈从栈底到栈顶为从小到大的顺序。

复杂度分析

时间复杂度

  • 最坏情况:在最坏情况下(即主栈中的元素按逆序排列时),每次需要将辅助栈中大量元素重新放回主栈,导致大量的元素被反复移动。因此,最坏情况的时间复杂度为 O(n²),其中 n 是栈中元素的数量。
  • 最好情况:在最好情况下(即主栈中的元素已经按顺序排列时),每个元素只需要移动一次,时间复杂度为 O(n)

空间复杂度

该算法使用了一个额外的辅助栈,因此空间复杂度为 O(n),其中 n 为栈中元素的数量。

完整代码及测试:

#include <iostream>
#define MAXSIZE 100
#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int Status;
using namespace std;
typedef struct
{
	int* base;
	int* top;
	int  stacksize;
}SqStack;
Status InitStack(SqStack& S)
{//栈初始化
	S.base = new int[MAXSIZE];
	if (!S.base)
		return ERROR;
	S.top = S.base;
	S.stacksize = MAXSIZE;

	return OK;
}
Status Push(SqStack& S, int e)
{//入栈
	if (S.top - S.base >= S.stacksize)
		return OVERFLOW;
	*S.top++ = e;

	return OK;
}
Status Pop(SqStack& S, int& e)
{//出栈
	if (S.top == S.base)
		return ERROR;
	e = *--S.top;

	return OK;
}
int GetTop(SqStack S)
{//取栈顶元素
	if (S.top == S.base)
		return ERROR;
	return *(S.top - 1);
}

void Out(SqStack s) {
	int* flag = s.top;
	while (flag > s.base) {
		cout << *(flag - 1) << " ";
		flag--;
	}
	cout << endl;
}

void SqSort(SqStack& s) {
	SqStack ts;//辅助栈
	InitStack(ts);

	while (s.top > s.base) {
		int temp1 = 0;
		Pop(s, temp1);

		//当辅助栈为空或者取出元素小于辅助栈栈顶元素时将temp1入辅助栈
		if (ts.base == ts.top || GetTop(ts) >= temp1) {
			Push(ts, temp1);
		}
		else {//当取出元素大于辅助栈栈顶元素时,将辅助栈内元素放回原栈,直到temp1小于辅助栈栈顶元素
			while (ts.base != ts.top&& GetTop(ts) < temp1){//注意此处的条件
				int temp2 = 0;
				Pop(ts, temp2);
				Push(s, temp2);
			}//由于辅助栈内是排好序的,按顺序取出入原栈,依然有序,放入temp1后这些元素将再次返回辅助栈
			Push(ts, temp1);
		}
	}

	//排序后将辅助栈元素返回到原栈中
	while (ts.base != ts.top) {
		int e;
		Pop(ts, e);
		Push(s, e);
	}

}

int main()
{
	SqStack s;
	InitStack(s);
	Push(s, 4);
	Push(s, 2);
	Push(s, 6);
	Push(s, 5);
	Push(s, 1);
	Push(s, 3);

	Out(s);

	SqSort(s);
	Out(s);

}

输出:

3 1 5 6 2 4
6 5 4 3 2 1

那么问题来了,用队呢?

询问GPT得到肯定的答案,此处我没有加以验证,也不再追述。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇