Linux C++:栈、队列、链表

博客介绍了数据结构中栈、队列、链表的相关知识,包括栈的后进先出、队列的先进先出、链表的非连续存储等特点,还阐述了程序内存分配,如栈、堆、自由存储区、全局存储区、常量存储区的分配和释放方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    在学习数据结构中,栈、队列、链表是几个比较重要的学习点。如何让数据有序的存储呢,但是在这之前那我们得先学习一些储备知识,那样才会让我们更好的往下学习。

程序内存分配(基础知识)

  1. 栈(stack): 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。 其操作如往箱子里面放衣服一样,只有一个出口,后进先出。
  2. 堆(heap):一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。其操作方式如同有出口和入口的景区,先进先出。
  3. 自由存储区:自由存储是C++中通过new与delete动态分配和释放对象的抽象概念,而堆(heap)是C语言和操作系统的术语,是操作系统维护的一块动态分配内存。(这里有点难理解,很多人认为自由存储区和堆是等价的,其实不然)
  4. 全局存储区(静态存储区):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后有系统释放。
  5. 常量存储区:这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改。

示例描述:

//test.cpp
int a = 0; //全局初始化区
int a = 0; //全局初始化区
char *p1; //全局未初始化区
main() {
    int b; //栈
    char s[] = "abc"; //栈
    char *p2; //栈
    char *p3 = "123456"; //123456\0在常量区,p3在栈上。
    static int c = 0; //全局(静态)初始化区
    int* nub = new int;
    int* nub1 = new int(5);
    //分配在自由存储区  new
    p1 = (char *)malloc(10);
    p2 = (char *)malloc(20);
    //分配得来得10和20字节的区域就在堆区。
    strcpy(p1, "123456"); //123456\0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。
    free(p1); //释放内存
    free(p2);
    delete nub;  //释放内存
    delete[] nub1;
}

数据结构:栈

栈:是一种连续存储的数据结构,特点是存储的数据先进后出。我们把表尾称作栈顶(top),相应的,表头称作栈底(bottom),由栈的特性可知,栈是一种后进先出(LIFO)的线性表,只能在栈顶进行插入和删除。包括:栈、链栈。

使用STL容器基于数组的栈操作:

#include <stack>
#include <iostream>

using namespace std;
 
int main()
{
	stack<int> Nstack;
	int sum = 0;

	for (int i = 0; i <= 10; i++){
		Nstack.push(i);
	}

	cout << "size is " << Nstack.size() << endl;

	while (!Nstack.empty()){
		cout << "-" << Nstack.top();
		Nstack.pop();
	}

	cout << endl;
    
	return 0;
}
// Nstack.empty();//如果栈为空则返回true, 否则返回false;
// Nstack.size(); //返回栈中元素的个数
// Nstack.top();  //返回栈顶元素, 但不删除该元素
// Nstack.pop();  //弹出栈顶元素, 但不返回其值
// Nstack.push(); //将元素压入栈顶

更多操作后续补充 

数据结构:队列

队列:队列是一种先进先出(FIFO)的线性表,它只允许在一边插入,而在另一边删除元素,我们把删除的一端称为队首(front),插入的一端称为队尾(rear)。包括单向队列、双向队列、循环队列。

基于STL容器数组队列示例(单向队列):

#include <queue>
#include <iostream>
#include <cstdlib>
using namespace std;
 
int main(){
	queue<int> q;
	for (int i = 0; i < 10; i++){
		q.push(i);
	}
	if (!q.empty()){
		cout << "队列q非空!" << endl;
		cout << "q中有" << q.size() << "个元素" << endl;
	}
	cout << "队头元素为:" << q.front() << endl;
	cout << "队尾元素为:" << q.back() << endl;
	for (int j = 0; j < 10; j++){
		int tmp = q.front();
		cout << tmp << " ";
		q.pop();
	}
	cout << endl;
	if (!q.empty()){
		cout << "队列非空!" << endl;
	}
	system("pause");
	return 0;
}
// q.empty()               如果队列为空返回true,否则返回false
// q.size()                返回队列中元素的个数
// q.pop()                 删除队列首元素但不返回其值
// q.front()               返回队首元素的值,但不删除该元素
// q.push()                在队尾压入新元素
// q.back()                返回队列尾元素的值,但不删除该元素

更多操作后续补充 

数据结构:链表

链表:链表是一种物理存储单元上非连续、非顺序的存储结构数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 相比于线性表顺序结构,操作复杂。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)。链表很好的克服了数组的缺点,它在内存中不需要连续的内存,插入或者删除操作o(1)时间复杂度就能解决,长度也是动态增长。如果你的元素需要频繁的进行插入、删除操作,那么链表就是个很好的选择。包括单向链表、双向链表、单向循环链表、双向循环链表。

简单链表实现:

//单向链表
#include <iostream>
using namespace std;
class node
{
public:
	int value;
	node *next;
	node()
	{
		value = 0;
		next = NULL;
	}
};
int main()
{	
	node *head,*curr;
	head = new node();
	head->next = NULL;
	head->value = 15;
	for (size_t i = 0; i < 10; i++)
	{
		curr = new node();
		curr->value = i;
		curr->next = head;
		head = curr;
	}
	//遍历
        for(int i = 0 ; i< 11; i++){
            cout << head->value <<endl;
            curr = head->next;
            head = curr;
        }
}

使用STL容器实现链表:

#include<iostream>
#include<list> 			//双向链表
#include<algorithm>
//#include<forward_list>  //单向链表
using namespace std;
 
typedef struct Node
{
	int a;
	char c;
    bool operator==(struct Node b) const  
   {  
	   return (this->a == b.a)&&(this->c == b.c);  
   }  
	
    bool operator!=(struct Node b) const  
   {  
	   return (this->a == b.a)&&(this->c == b.c);  
   }   
	
    bool operator>=(struct Node b) const  
   {  
	   return (this->a == b.a)&&(this->c == b.c);   
   }    
   
    bool operator<=(struct Node b) const  
   {  
	   return (this->a == b.a)&&(this->c == b.c);  
   }  
 
    bool operator>(struct Node b) const  
   {  
	   return (this->a == b.a)&&(this->c == b.c);   
   }  
	 
    bool operator<(struct Node b) const  
   {  
	   return (this->a == b.a)&&(this->c == b.c);  
   }  
}Nodes;
 
void fun(Nodes& d)
{
	cout << d.a << "-" << d.c << "\n";
}
 
int main()
{
    Nodes nu={12,'a'};
    Nodes nu1 = {20,'c'};
	list<Nodes> ls(6,nu);
	cout << ls.size() << endl;
    list<Nodes>::iterator iter;
    for(iter = ls.begin(); iter != ls.end() ;iter++)
    {
        cout<< iter->a <<"-"<<iter->c<<endl;
    }
    
    cout<<"迭代器只能进行自加\n";
    //迭代器只能进行自加
    iter++;iter++;
    list<Nodes> ls2(iter,ls.end());
	for_each(ls2.begin(),ls2.end(),fun);

    cout<<"重置大小\n";
	//重置大小
	ls.resize(3);
	cout << ls.size() << endl;
	for_each(ls.begin(),ls.end(),fun);

    cout<<"插入尾\n";
	//插入尾
    ls.push_back(nu1);
    for_each(ls.begin(),ls.end(),fun);

    cout<<"插入头\n";
    //插入头
    ls.push_front(nu1);
    for_each(ls.begin(),ls.end(),fun);

    cout<<"删除尾节点\n";
    ls.pop_back();
    for_each(ls.begin(),ls.end(),fun);

    cout<<"删除头节点\n";
    ls.pop_front();
    for(iter = ls.begin(); iter != ls.end() ;iter++)
    {
        cout<< iter->a <<"-"<<iter->c<<endl;
    }

    cout<<"在二 三之间插入节点id 2 ins\n";
    Nodes ins = {55,'v'};
    int id =0;
    for(iter = ls.begin(); iter != ls.end() ;iter++)
    {
        if(id == 2){
            //指向新插入的iter
            iter = ls.insert(iter,ins);
            cout<< iter->a <<"-"<<iter->c<<endl;
            break;
        }
        cout<< iter->a <<"-"<<iter->c<<endl;
        ++id;
    }

    cout<<"查找ins\n";
    iter = find(ls.begin(),ls.end(),ins);
    if(iter != ls.end())cout<<"I find it ,ins-Existent"<<endl;
    else
    {
        cout<<"I not find it ,ins-Non-existent"<<endl;
    }

    Node loos={99,'y'};
    iter = find(ls.begin(),ls.end(),loos);
    if(iter != ls.end())cout<<"I find it ,loos-Existent"<<endl;
    else
    {
        cout<<"I not find it ,loos-Non-existent"<<endl;
    }
    cout<<"删除ins\n";
    ls.remove(ins);
    for_each(ls.begin(),ls.end(),fun);

    cout<<"清空链表 使用遍历清空,避免内存泄露"<<endl;
    for(iter = ls.begin();iter != ls.end();){
        //iter指向了下一个元素
        iter = ls.erase(iter);
        cout<<"删除中...."<<endl;
    }

	if(ls.empty())	cout << "empty" << endl;
	else cout << "No empty" <<endl; 
	
	return 0;
}

待续...

参考文章:

https://blog.youkuaiyun.com/zichen_ziqi/article/details/80807989

https://blog.youkuaiyun.com/AAMahone/article/details/81148419

https://blog.youkuaiyun.com/zichen_ziqi/article/details/80819939

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值