数据结构遍历顺序栈_数据结构之栈(三):顺序栈实现

顺序栈的实现和使用数组实现原理一样,都是预先申请一段连续的地址块作为数据域,通过栈顶下标或指针移动完成压栈、出栈等操作。不同的是,使用指针的顺序栈支持栈满时扩容操作,原理更倾向于vector的实现。

顺序栈初始化时申请一块固定大小内存空间保存数据,栈顶指针在内存区域来回移动:

2ceeea53b03108a1b5a32d4159b836ac.png

要注意的是,初始时栈为空,bottom和cursor指针都是指向同一个区域,每插入一个元素,给cursor所在的元素赋值,然后cursor后移一位。

c3523a863266b982bd372e5c71d1990e.png

不难发现,cursor指针所指向的区域是空的,它所在位置的前一个元素才是真正的栈顶元素,所以每次取栈顶元素或者执行出栈操作时,要先把指针前移一位,然后再弹出cursor所指向的元素。

所以根据这个原则,当栈满的时候,cursor实际所指向的地址已经越界,它位于最后一个元素地址空间的下一个:

87c84049a67279abd9f0e6cd822b828f.png

此时虽然指针已经非法,但是实际上并不会取到这个地址上的值,所以也不会导致内存错误。这也要求在处理压栈、出栈操作时要小心,不要取向非法内存地址上的值。

对于这个问题也有一个解决的方法,就是在申请内存空间时多申请一个地址,最后多的一个数据块出来存放栈满后的cursor,相对来说这个方法更为安全保险。

类定义

#ifndef _UNSIGNED_INT_

#define uint unsigned int

#endif // !_UNSIGNED_INT_

template

class CSeqStack {

public:

CSeqStack();

~CSeqStack();

void push(const T& data);

T pop();

T& top() const;

uint size() const;

bool empty() const;

private:

T * bottom;

T* cursor;

uint cap;

};

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

#ifndef _UNSIGNED_INT_

#define uint unsigned int

#endif // !_UNSIGNED_INT_

template

classCSeqStack{

public:

CSeqStack();

~CSeqStack();

voidpush(constT&data);

Tpop();

T&top()const;

uintsize()const;

boolempty()const;

private:

T*bottom;

T*cursor;

uintcap;

};

类实现

template

inline CSeqStack::CSeqStack()

{

bottom = new T[N] + 1;

// bottom = new T[N];

cursor = bottom;

cap = N;

}

template

inline CSeqStack::~CSeqStack()

{

delete[]bottom;

}

template

inline void CSeqStack::push(const T & data)

{

// 容量不足了,重新申请

if (cursor - bottom == cap) {

uint newCap = cap + 1;

// 根据当前容量的两倍扩容

T* tmp = new T[newCap * 2 + 1]; // 多申请一个内存空间

// T* tmp = new T[newCap * 2];

// 拷贝内存

memcpy(tmp, bottom, sizeof(T)*cap);

// 对栈顶指针重新赋值

cursor = tmp + (cursor - bottom);

delete[]bottom;

// 重新赋值栈底指针

bottom = tmp;

cap = newCap * 2;

}

*(cursor++) = data;

}

template

inline T CSeqStack::pop()

{

// 栈顶元素时cursor指向的前一个元素

T tmp = *(--cursor);

return tmp;

}

template

inline T & CSeqStack::top() const

{

// 栈顶元素时cursor指向的前一个元素

return *(cursor - 1);

}

template

inline uint CSeqStack::size() const

{

// 两个指向同一数组的指针相减得到两个元素间的距离

return cursor - bottom;

}

template

inline bool CSeqStack::empty() const

{

return cursor == bottom;

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

template

inlineCSeqStack::CSeqStack()

{

bottom=newT[N]+1;

// bottom = new T[N];

cursor=bottom;

cap=N;

}

template

inlineCSeqStack::~CSeqStack()

{

delete[]bottom;

}

template

inlinevoidCSeqStack::push(constT&data)

{

// 容量不足了,重新申请

if(cursor-bottom==cap){

uintnewCap=cap+1;

// 根据当前容量的两倍扩容

T*tmp=newT[newCap*2+1];// 多申请一个内存空间

// T* tmp = new T[newCap * 2];

// 拷贝内存

memcpy(tmp,bottom,sizeof(T)*cap);

// 对栈顶指针重新赋值

cursor=tmp+(cursor-bottom);

delete[]bottom;

// 重新赋值栈底指针

bottom=tmp;

cap=newCap*2;

}

*(cursor++)=data;

}

template

inlineTCSeqStack::pop()

{

// 栈顶元素时cursor指向的前一个元素

Ttmp=*(--cursor);

returntmp;

}

template

inlineT&CSeqStack::top()const

{

// 栈顶元素时cursor指向的前一个元素

return*(cursor-1);

}

template

inlineuintCSeqStack::size()const

{

// 两个指向同一数组的指针相减得到两个元素间的距离

returncursor-bottom;

}

template

inlineboolCSeqStack::empty()const

{

returncursor==bottom;

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值