顺序容器相关内容总结

本文就数组、链表、队列、栈(顺序容器)进行常识性的介绍和总结,文章先分别介绍各部分知识点,最后进行对比总结。

          一、 数组

        用C和C++实现数组的方式是有区别的;

       C通过:类型 数组名【数组大小】 显示定义数组的类型和大小,并且根据内置类型初始化规则进行初始化.比如int a[10]定义a是含有10个元素的整型数组,int默认初始化为0.用C实现的数组大小不能动态实现,如果在实际应用中数组容量不够,必须通过定义一个更大的数组将初始数组复制过去,再将小的数组删除,(通过malloc()和free()函数进行内存的分配和释放)因此在使用时通常将数组定义成足够大,所以会存在内存空间浪费的现象。

       C++通过:STL标准库vector来实现,以vector 定义数组,可以指定数组的类型,根据type的类型来选择是利用内置类型、符合类型或提供了默认构造函数的类类型来进行初始化,vector容器有容量和长度之分,通常容量>长度,并且可以根据vecotor类的接口函数进行复制、赋值、访问、重新设定数组大小等操作,数组的大小可以动态实现。(通过new和delete操作符进行内存的分配和释放)。由于数组在内存当中是连续存储的,因此可以利用下标进行索引,随机访问很方便。

       测试程序:

#include <iostream>
#include <vector>
using namespace std;

int main()
{
	int a[10]={1,2,3};
	cout<<"数组a:"<<endl;
	for(int i=0;i<10;i++)
		cout<<a[i]<<" ";
	cout<<endl;
	vector<int> b(10);//b(10)初始化前10个元素为0
	b.push_back(1);
	b.push_back(2);
	b.push_back(3);
	cout<<"数组b的长度:"<<b.size()<<endl;
	cout<<"数组b的容量:"<<b.capacity()<<endl;
	cout<<"数组b:"<<endl;
	for(vector<int>::iterator iter=b.begin();iter != b.end();iter++)
		cout<<*iter<<" ";
	cout<<endl;
	system("pause");
	return 0;
}

         二、 链表


         数组实现了数据的顺序存储,便于元素的随机访问,但是不利于删除和插入元素,并且容易造成内存空间的浪费,链表解决数组的这些缺点,内存空间利用率高,并且易于删除和插入,但是不利于随机访问,只能通过遍历链表来实现随机访问,效率不高。C++使用STL中的List类定义的方法来实现链表的各项操作。
链表从逻辑结构上分为单向链表和双向链表和循环链表。
        下面结合《程序员面试宝典-3》中的相关例题进行链表分析:

    1.单链表:实现单链表的建立、测长、打印、插入、删除、排序功能。

//实现单链表的建立、测长、打印、插入、删除、排序、逆置功能。

#include <iostream>
using namespace std;

typedef struct student
{
	int data;
	struct student *next;
}node;

//链表的建立
node *creat()
{
	node *head,*p,*s;//head用来做返回值,p创建链表的移动指针,s用于添加元素时创建结点
	head= new node;
	p=head;
	int x;
	int cycle=1;//用户判定是否继续输入,0停止建立链表
	while(cycle)
	{
		cout<<"please input the data:"<<endl;
		cin>>x;
		if(x!=0)
		{
			s=new node;
			s->data=x;
			p->next=s;
			p=s;
		}
		else cycle=0;
	}
	head=head->next;
	p->next=NULL;
	return head;
}

//链表的测长
int length(node *head)
{
	int n=0;
	node *p=head;
	while(p!=NULL)
	{
		p=p->next;
		n++;
	}
	return n;
}

//链表的打印
void print(node *head)
{
	node *p=head;
	while(p!=NULL)
	{
		cout<<p->data<<" ";
		p=p->next;
	}
	cout<<endl;
}

//链表的插入
node *insert(node *head,int num)
{
	node *p0=new node;
	node *p1=head;
	node *p2;
	p0->data=num;
	if(p0->data<=head->data)
	{
		p0->next=p1;
		head=p0;
	}
	else //if(p0->data>head->data)
	{
		while(p0->data>p1->data && p1->next !=NULL)
		{
			p2=p1;
			p1=p1->next;
		}
		if(p1->next !=NULL || p0->data <=p1->data ) //还没到末尾
		{
			p2->next=p0;
			p0->next=p1;
		}
		else //末尾
		{
			p1->next=p0;
			p0->next=NULL;
		}
	}
	return head;
}

//链表的删除
node *del(node *head,int num)
{
	node *p1=head;
	node *p2;
	if(num==p1->data)
	{
		head=p1->next;
		delete p1;
	}
	else
	{
		while(num!=p1->data && p1->next !=NULL)
		{
			p2=p1;
			p1=p1->next;
		}
		if(num==p1->data )
		{
			p2->next=p1->next;
			delete p1;
		}
		else 
			cout<<"该链表没有元素:"<<num<<endl;
	}
	return head;
}

//链表的排序
node *sort(node *head)
{
	node *p0;
	int n=length(head);
	int temp;
	if(head==NULL || head->next==NULL)
		return head;
	p0=head;
	for(int i=1;i<n;i++)
	{
		p0=head;
		for(int j=0;j<n-i;j++)
		{
			if(p0->data>p0->next->data)
			{
				temp=p0->next->data;
				p0->next->data=p0->data;
				p0->data=temp;
			}
			p0=p0->next;
		}
	}
	return head;
}

//链表的逆置
node *reverse(node *head)
{
	node *p1,*p2,*p3;
	if(head==NULL || head->next==NULL)
		return head;
	p1=head,p2=p1->next;
	while(p2)
	{
		p3=p2->next;
		p2->next=p1;
		p1=p2;
		p2=p3;
	}
	head->next=NULL;
	head=p1;
	return head;
}

int main()
{
	node *list;
	int leng;
	cout<<"建立链表:"<<endl;
	list=creat();
	list=insert(list,4);
	list=del(list,1);
	leng=length(list);
	cout<<"建立的链表长度为:"<<leng<<endl;
	cout<<"打印链表:"<<endl;
	print(list);
	sort(list);
	cout<<"排序后打印链表:"<<endl;
	print(list);
	list=reverse(list);
	cout<<"逆置后打印链表:"<<endl;
	print(list);
	system("pause");
	return 0;
}

      

        2.双链表:建立、测长、打印、删除、插入

 

//实现双向链表的建立、删除和插入

#include <iostream>
using namespace std;

typedef struct student
{
	int data;
	struct student *next;
	struct student *prev;
}dnode;

//建立链表
dnode *creat()
{
	dnode *head,*p,*s;
	int x,cycle=1;
	head=new dnode;
	p=head;
	while(cycle)
	{
		cout<<"please enter the data:";
		cin>>x;
		//cout<<endl;
		if(x!=0)
		{
			s=new dnode;
			s->data=x;
			p->next=s;
			s->prev=p;
			p=s;
		}
		else
			cycle=0;
	}
	p->next=NULL;
	head=head->next;
	head->prev=NULL;
	return head;
}

//链表测长
int length(dnode *head)
{
	int n=0;
	dnode *p=head;
	while(p!=NULL)
	{
		p=p->next;
		n++;
	}
	return n;
}

//链表的打印
void print(dnode *head)
{
	dnode *p=head;
	while(p!=NULL)
	{
		cout<<p->data<<" ";
		p=p->next;
	}
	cout<<endl;
}

//删除链表结点
dnode *del(dnode *head,int num)
{
	dnode *p=head;
	while(num !=p->data && p->next !=NULL)
	{
		p=p->next;
	}

	if(num==p->data)
	{
		if(p==head)
		{
			head=head->next;
			head->prev=NULL;
			delete p;
		}
		else if(p->next==NULL)
		{
			p->prev->next=NULL;
			delete p;
		}
		else
		{
			p->prev->next=p->next;
			p->next->prev=p->prev;
			delete p;
		}
	}
	else
		cout<<"该链表中没有要删除的元素:"<<endl;
	return head;
}

//插入链表结点
dnode *insert(dnode *head,int num)
{
	dnode *p=head,*s;
	s=new dnode;
	s->data=num;
	while(num>p->data && p->next !=NULL)
	{
		p=p->next;
	}
	if(num<=p->data)
	{
		if(p==head)
		{
			p->prev=s;
			s->next=p;
			head=s;
		}
		else
		{
			p->prev->next=s;
			s->next=p;
			s->prev=p->prev;
			p->prev=s;
		}
	}
	else
	{
		p->next=s;
		s->prev=p;
		s->next=NULL;
	}
	return head;
}


int main()
{
	dnode *dlist;
	int leng;
	dlist=creat();
	leng=length(dlist);
	cout<<"链表长度为:"<<leng<<endl;
	cout<<"打印链表:"<<endl;
	print(dlist);
	dlist=del(dlist,4);
	cout<<"删除元素后打印链表:"<<endl;
	print(dlist);
	dlist=insert(dlist,5);
	cout<<"插入元素后打印链表:"<<endl;
	print(dlist);
	//cout<<""<<endl;
	system("pause");
	return 0;
}


          3.循环链表不做详细介绍。

          三、 数组与链表的区别
         1.从逻辑结构上看:数组必须预先定义好固定的长度大小,不能动态改变内存大小,当数据增加超过数组容量时必须重新定义一个更大的数组,并将原始数组复制过去,当数据减小时,数组大小并不会减小,因此数组的内存利用率低且不灵活。链表能通过new和delete等操作符动态进行分配内存,且很方便的插入和删除数据项。
        2.从内存存储看:数组从栈中分配空间,因此空间的分配和回收由编译器完成,程序员方便,但自由度小。链表从堆中分配空间,空间的分配和释放必须由程序员管理。
        3.从访问方式看:数组是顺序连续存储,可以利用下标进行访问,随机访问很方便,但是插入删除工作量很大。链表是链式存储结构,便于插入删除,但是访问效率比数组低。

        四、 队列
        先进先出FIFO,主要用于文件服务器,排队理论。

       五、 栈
      是后进先出LIFO表,主要用在平衡符号,后缀表达式,函数调用,中缀到后缀的转变等方面。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值