您的位置:首页 > 理论基础 > 数据结构算法

基本数据结构——栈、队列和单链表

2012-12-03 14:32 295 查看
按照《IA》的说法,基本数据结构还包括有根树,但我这里想把这三个单独拿出来总结,有根树放在二叉查找树、红黑树和字典树这样的实例中总结。

栈、队列和单链表,都属于线性表的内容,都具有线性结构的特点,其形式化的表述为:

1、存在唯一的一个被称为“第一个”的数据元素;

2、存在唯一的一个被称为“最后一个”的数据元素;

3、除第一个之外,集合中的每个数据元素均只有一个前驱;

4、除最后一个外,集合中的每一个元素都只有一个后继。

简单的理解,可以认为,所谓线性表,是指从第一个到最后一个元素,有且仅有一条遍历所有数据元素的路线。

栈和队列都是一种特殊的线性表,栈是入栈(Insert)和出栈(pop)操作均针对栈顶元素的线性表,即通常所说的后进先出(LIFO),而队列则是进队在队尾,出队在队头的线性表,通常称之为先进先出“FIFO”。

栈在计算机中最大的应用就是函数调用时断点信息的保存以及局部变量的存储。

栈还有一些其他的应用,如整除倒取余的数制转换、括号匹配、穷举法迷宫求解、表达式求值等等,尤其是在函数的递归调用中,比如求解斐波那契数列,栈的存在大大简化了代码的编写,当然由于重复计算,此时算法的时间效率并不理想,不适合规模过大的问题,是不是可以应用查表的方式改善?

队列的主要应用则在于多线程间信息的存储和读取。

栈和队列可以用顺序结构实现,比如数组:

可以用数组S
来实现一个至多有n个元素的栈,该数组有个属性top(S),来指向最近插入的元素。

有关栈的三种基本操作:

Stack_Empty(S)

if(top(S)==0)

return TRUE

else return FALSE

PUSH(S,x)

top(S)=top(S)+1

S[top(S)]=x

POP(S)

if Stack_Empty(S)

error "underflow"

else

top(S)=top(S)-1

return S[top(S)+1]

进队和出队的操作类似,需要注意的是进队和出队都要检测溢出。

线性表还可以用非连续的的方式存储,即线性链表或单链表,在单链表的一个节点中,包含两个域:数据域和指针域,即data和next



单链表原理简单,但基于单链表的问题往往非常巧妙,基本操作如单链表的建立、测长、遍历、插入、删除、排序、逆置势必需要掌握的,其他像如何判断单链表是否有环,环的入口和长度,两个单链表是否相交(如相交则求相交的第一个元素)等等也需要熟悉,后面这些单独总结吧,附几个基本操作的C++代码:

#include <iostream>
using namespace std;

typedef struct student
{
int data;
student *next;
}node;
//创建链表
node *Create()
{
node *head,*pNow,*temp;
int data,cycle=1;
head=new node;
pNow=head;
while(cycle)
{
cout<<"please enter a num"<<endl;
cin>>data;
if(data!=0)
{
temp=new node;
temp->data=data;
pNow->next=temp;
pNow=temp;
}
else
cycle=0;
}
pNow->next=NULL;
head=head->next;
cout<<head->data<<endl;
return head;
}
//使用遍历的方法测量链表长度
int GetLength(node *head)
{
int length=0;
node *pNow;
pNow=head;
while(pNow!=NULL)
{
length++;
pNow=pNow->next;
}
return length;
}
//遍历
void Print(node *head)
{
node *pNow=head;
while(pNow!=NULL)
{
cout<<pNow->data<<endl;
pNow=pNow->next;
}
}
//删除链表中的某个值,插入的考量类似,链表的排序可以采用选择排序的策略
node *delElement(node *head,int data)
{
node *pNow=head;
node *pre=pNow;
while(pNow->data!=data&&pNow->next!=NULL)
{
pre=pNow;
pNow=pNow->next;
}
if(pNow->data==data)
{
if(pNow==head)
{
head=pNow->next;
delete pNow;
}
else
{
pre->next=pNow->next;
delete pNow;
}
}
else
{
cout<<"Couldnt find num"<<data<<endl;
}
return head;
}
//链表的逆置,需要一个临时变量保存pre节点
node *Reve(node *head)
{
node *pre,*pNow,*temp;
if(head==NULL||head->next==NULL)
return head;
pre=head;
pNow=head->next;
pre->next=NULL;
while(pNow->next!=NULL)
{
temp=pNow->next;
pNow->next=pre;
pre=pNow;
pNow=temp;
}
pNow->next=pre;
head=pNow;
return head;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: