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

数据结构与算法之----线性表

2015-03-17 11:16 155 查看

1、线性表的顺序存储结构

1.1 顺序表的创建和遍历

#include "stdafx.h"
#include<iostream>
#include<string.h>
using namespace std;
struct Sqlist
{
int *data;
int length;
int maxsize;
Sqlist():length(0){}
};
void ListInsert(Sqlist &L,int i,int e)
{
if(L.length==L.maxsize ||(i<0||i>L.length))//判断是否已满 或者i不在范围之内,但是要考虑到在末尾插入的情况
{
cout<<"out of range"<<endl;
return;
}
for(int a=L.length;a>i;a--)
{
L.data[a]=L.data[a-1];
}
L.data[a]=e;
L.length++;
}
void PrintList(Sqlist &L)
{
for(int i=0;i<L.length;i++)
{
cout<<L.data[i];
}
cout<<'\n';
}
int _tmain(int argc, _TCHAR* argv[])
{
Sqlist L;
cout<<"请输入顺序表长度"<<endl;
cin>>L.maxsize;
L.data=new int[L.maxsize]();

for(int i=0;i<5;i++)
{
int e;
cin>>e;
ListInsert(L,i,e);
}
PrintList(L);

}
输出:
请输入顺序表长度

10

8 7 6 5 4

87654

Press any key to continue
思想:
(1)注意在插入的时候,位置的选择,只能是在[0,length]上,否则会造成空隙,不好操作。
(2)这种游标方式,比书上的看起来更加方便,从尾部开始,用前面的值覆盖后面的值
(3)要注意判断是否满了的情况
(4)插入之后length++

1.2顺序表的删除

void DeleteList(Sqlist &L,int i,int &e)
{
if(i<0 || i>=L.length)
{
cout<<"out of range"<<endl;
return;
}
else
{
e=L.data[i];
for(int a=i;a<L.length-1;a++)
L.data[a]=L.data[a+1];
L.length--;  //千万不要忘了使 length-1,否则会出问题,因为原来数组末尾中的元素是没有删除的
}

}
思想:
(1)千万不要忘记length--
(2)从i开始,利用后面的值覆盖前面的值

2、线性表的链式存储结构

2.1、线性表的整表创建、遍历、整表删除

#include "stdafx.h"
#include<iostream>
#include<string.h>
using namespace std;
struct Node
{
int data;
Node *next;
Node():next(NULL),data(0){}
};
void CreateList(Node *L)//整表创建
{
int a;
while(1)//不要忘了这个1,这里的插入法无需用递归,因为不需要子操作就能完成
{
cin>>a;
if(a==8)return;
Node *p=new Node();//前插法
p->data=a;
p->next=L->next;
L->next=p;
}

}

void PrintList(const Node *L)
{
Node *p=L->next;//指向第一个
while(p)
{
cout<<p->data;
p=p->next;
}
cout<<'\n';

}

void EmptyList(Node *L)
{
if(L->next)EmptyList(L->next);
cout<<L->data;
delete L;
}
int _tmain(int argc, _TCHAR* argv[])
{
Node *L=new Node();
CreateList(L);
PrintList(L);
EmptyList(L);
return 0;

}


输出:
3 7 6 5 4 8

45673

376540Press any key to continue

思想:
(1)首先要创建表头,为了跟后面节点风格统一,头结点也用new来创建,那么整个链表就都可以用指针来传递,方便后面的删除递归操作。
(2)整表创建,这里可以用前插,或者后插法,利用while(1)循环来控制插入个数
(3)整表遍历,同样用while(not null),遍历链表即可。
(4)整表删除,用递归的方式,递归体为,若还有子节点,那么先删除子节点,再删除自己,注意这个是并列的操作,是一起完成的。递归出口,显然就是没有子节点了。
(5)while(p)和while(p->next)的区别是 前者最后p指向的是空的,而对于后者,指向的是最后一个元素。所以后者对于插入而言是不错的

2.2、链表的插入、删除操作

插入
void ListInsert(Node *L,int i,int e)
{
Node *p=L;
int j=0;
while(j<i && p->next!=NULL)//同样要考虑在第0个和最后一个后面插入的情况,因此,指针指向插入前的位置
{
p=p->next;
j++;
}
if(j==i)//若i在长度范围内,那么执行插入操作,这里的j相当于一个计数器,而且是在链表长度范围内的,因为有P的判断控制
{
Node *node=new Node;
node->data=e;
node->next=p->next;
p->next=node;

}
else
cout<<"out of range"<<endl;

}
思想:
(1)对于链表的操作,进行遍历的时候,一定要用另外一个指针来遍历,也就是说,不要改变原来指针的位置。
(2)while的判断,一般要判断其下一个是否为空,所以用p-next进行判断最好,即进行了判断,而且指针最后停在了有值的位置。不会溢出

删除
void ListDelete(Node *L,int i)
{
Node *p=L;
int j=0;
while(j<i && p->next!=NULL)
{
p=p->next;
j++;
}
if(j==i && p->next!=NULL)//这个就是和插入 遍历之后的一点小区别,因为插入可以在最末尾,空的位置插入,但是不能删除空的位置
{
Node *node=p->next;
p->next=node->next;
delete node;
}
else
cout<<"out of range"<<endl;
}

输出:
3 7 6 5 4 8

45673

删除之后为

4573

37540Press any key to continue

思想:
(1)遍历方式和插入完全一样,都需要找到插入位置的前一个
(2)删除操作唯一不同的时候,是需要先判断定位的下一个是否是空的,为空的话是不需要删除的,否则会出问题,而对于插入,当是空的时候是可以插入的。

3、循环链表

要将一个链表编程循环链表,可以这么做:

(1)存储头指针

(2)遍历链表,指向队尾,将尾部的next指向头指针,返回队尾,下次访问的时候,第一个就是访问尾部,通过尾部,也可以访问头指针,形成了循环链表

(3)这种结构的好处就是,可以轻松将两个这样的循环链表连接成一个循环链表,只需要做一些简单的指针修改即可,不需要再遍历一个链表。

4、双向链表

(1)就是设置两个指针地域,一个指向前驱prior 一个指向next

(2)头指针的前驱为尾指针,尾指针的后继为前指针

(3)这样就形成了双向链表。

(4)有时间要尝试构造下,应该不难
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: