一、基本概念
1、线性表:简称表,是n(n>=0)个具有相同类型的数据元素的有限序列,线性表中数据元素的个数称为线性表的长度。长度为零时称为空表。
2、线性表的顺序存储结构称为顺序表。
3、单链表:单链表是一组任意的存储单元存放线性表的位置,这组存储单元可以连续也可以不连续,甚至可以零散分布在内存中的任意位置。
下面着重介绍有关单链表的操作:
#include<iostream>
using namespace std;
const int maxsize = 10;
// 定义单链表的结点
struct Node
{
int data;
struct Node *next;
};
// linklist 类的声明
class linklist
{
public:
linklist(); // 建立只有头结点的单链表
linklist(int a[],int n); // 建立有N个元素的单链表
~linklist(); // 析构函数
void insert(int i,int x); // 在单链表的第 i 个位置插入元素值为 x 的结点
int Delete(int i); // 在单链表中删除第 i 个结点
int locate(int x); // 在单链表中 按值 查找 元素为x的元素 的位置(序号)
void printlist(); // 按序号依次输出各元素
private :
Node *first; // 单链表的头指针。
};
linklist::linklist()
{
first = new Node; // 生成头结点
first ->next=NULL; // 头结点指针域 置空
}
linklist::linklist(int a[],int n)
{
Node *r,*s;
first = new Node; // 生成头结点
r = first; // 尾指针 初始化
for(int i = 0;i<n;i++)
{
s=new Node;
s->data= a[i]; // 为每个元素建立一个结点
r->next= s;r=s; // 将结点s插入到终端结点之后
}
r->next = NULL; // 将终端指针域置空
}
linklist::~linklist()
{
Node *q = NULL;
while(first!=NULL)
{
q = first;
first = first->next;
delete q;
}
}
void linklist::insert(int i,int x)
{
Node *p = first,*s = NULL; // 工作指针p指向头结点
int count = 0;
while(p!=NULL&&count<i-1) // 查找第 i - 1个结点
{
p = p->next;
count++;
}
if(p==NULL) throw "位置";
// 将结点s 插入到p所指的i - 1 之后
else{
s= new Node;s->data= x;
s->next=p->next;
p->next = s;
}
}
int linklist::Delete(int i)
{
Node *p = first,*q=NULL;
int x;
int count = 0;
while(p!=NULL&&count<i-1)
{
p = p->next;
count++;
}
// 因为我们上面查找的是i - 1这个位置,删除的却是 i ,所以p-> next 也不能为空
if(p == NULL&&p->next ==NULL) // 这里很重要!!结点p 或 p的后继结点不存在
throw"位置";
else{
q = p->next;x = q->data; // 暂存被删结点
p->next = q->next; // 摘链
delete q;
return x;
}
}
int linklist::locate(int x)
{
Node *p = first -> next; //工作指针p初始化
int count = 1;
while(p != NULL)
{
if(p -> data == x) return count;
p = p -> next;
count++;
}
return 0;
}
void linklist::printlist()
{
Node *p = first->next;
while(p!=NULL)
{
cout<<p->data<<" ";
p=p->next;
}
cout<<endl;
}
int main()
{
int r[5]={1,2,3,4,5};
linklist L(r,5); // 建立单链表!
cout<<"执行操作前数据为:"<<endl;
L.printlist();
try
{
L.insert(2,3); // 在第二个位置插入3.
}
catch(char *s)
{
cout<<s<<endl;
}
cout<<"执行插入操作后的数据"<<endl;
L.printlist();
cout<<"值为5的元素 位置 为:";
cout<<L.locate(5)<<endl;
cout<<"执行删除操作前的数据为"<<endl;
L.printlist();
try
{
L.Delete(1); // 删除第一个位置的元素;
}
catch(char *s)
{
cout<<s<<endl;
}
cout<<"执行删除操作后的数据为:"<<endl;
L.printlist();
return 0;
}
4、循环链表:在单链表中,如果将终端结点的指针域由空指针改为指向头结点,就使整个单链表形成一个环,这种头尾相接的单链表称为循环单链表,简称循环链表。
5、双链表: 在循环链表中,虽然从任一结点出发可以扫描到其他结点,但要找到其他前驱结点,则需要遍历整个循环链表。如果希望快速确定表中任一结点的前驱结点,可以在单链表的每个结点中再设置一个指向其前驱结点的指针域,这样就形成了双链表。
6、静态链表:静态链表是用数组来表示单链表,用数组元素的下标来模拟单链表的指针。
7、间接寻址:是将数组和指针结合起来的一种方法,它将数组中存储数据元素的单元改为存储指向该元素的指针。