线性表
-
概念:一个线性表是n个具有相同特性的数据元素的有限序列,
-
特性:
1.集合中必存在唯一的一个“第一元素”。
2.集合中必存在唯一的一个 “最后元素” 。
3.除最后一个元素之外,均有唯一的后继(后件)。
4.除第一个元素之外,均有唯一的前驱(前件)。
线性表应该实现的接口及基本方法如下(健壮性暂且不谈)
interface IListDS<T>
{
int GetLength(); //取得长度
void Clear(); //清空内部
bool isEmpty(); //判断线性表是否为空
void Add(T item);//添加元素
void Insert(T item, int i);//插入元素
T Delete(int i); //删除操作
T GetElement(int i); //按索引查找
T this[int index] { get; } //定义一个索引器,获得元素
int Locate(T value); //按值查找
}
顺序表
- 原理:顺序表存储是将数据元素放到一块连续的内存存储空间,相邻数据元素的存放地址也相邻(逻辑与物理统一)。
-
优点:
(1)空间利用率高。(局部性原理,连续存放,命中率高)
(2)存取速度高效,通过下标来直接存储。
- 缺点:
(1)插入和删除比较慢,比如:插入或者删除一个元素时,整个表需要遍历移动元素来重新排一次顺序。
(2)不可以增长长度,有空间限制,当需要存取的元素个数可能多于顺序表的元素个数时,会出现"溢出"问题.当元素个数远少于预先分配的空间时,空间浪费巨大。
-
时间性能:查找O(1),插入删除O(n)
-
代表类型:数组
- 适用情况:查找很多,插入和删除较少,例如堆排序和二分查找法
基础变量
private T[] data ; //存储的数据
private int count=0; //存储的数据个数
添加方法
public void Add(T item)
{
if (count == data.Length)
{
Console.WriteLine("当前顺序表已经存满,不允许在存储");
}
else
{
data[count] = item;
count++;
}
}
取数据方法
public T GetElement(int index)
{
if (index >= 0 && index <= count - 1) //索引值是否存在
{
return data[index];
}
else
{
Console.WriteLine("索引不存在");
return default(T);
}
}
public T this[int index] //索引器
{
get { return GetElement(index); }
}
删除方法
public T Delete(int index)
{
for(int i=index;i<count;i++)
{
data[i]=data[i+1]; //后位元素向前进1
}
count--;
}
插入方法
public void Insert(T item,int index)
{
if(index>=0&&index<=count-1)
{
for(int i=count-1;i>=index;i--)
{
data[i+1]=data[i]; //自第i位每个元素向后移动一位
}
data[index]=item; //插入item元素
count++;
}
}
单链表(链表)
- 概念:链表由节点组成,自首节点(head)开始,每个节点包含自身数据和指向下个节点的指针,可向下寻找但不可溯源。
- 优点:
(1)存取某个元素速度慢。
(2)插入和删除速度快,保留原有的物理顺序,比如:插入或者删除一个元素时,只需要改变指针指向即可。
(3)没有空间限制,存储元素的个数无上限,基本只与内存空间大小有关.
- 缺点:
(1)占用额外的空间以存储指针(浪费空间,不连续存放,malloc开辟,空间碎片多)
(2)查找速度慢,因为查找时,需要循环链表访问,需要从开始节点一个一个节点去查找元素访问。
- 时间性能:查找O(n),插入删除O(1)
- 代表类型:List
- 适用情况:插入和删除较多,查找较少
基本变量
private T data; //存储数据
private Node<T> next; //指针 指向下一个元素
构造方法
public Node()
{
this.data=default(T);
this.next=null;
}
public Node(T value)
{
this.data=value;
this.next=null;
}
public Node(T value,Node<T> next)
{
this.data=value;
this.next=next;
}
public Node(Node<T> next)
{
this.next=next;
}
添加方法
public void Add(T item)
{
Node<T> newNode = new Node<T>(item); //根据新的数据创建一个新的节点
//如果头结点为空,此节点为头结点
if (head==null)
{
head = newNode;
}
else //把新来的节点放到链表的尾结点
{
Node<T> temp = head;
while (true)
{
if (temp.Next != null)
{
temp = temp.Next;
}
else
{
break;
}
}
temp.Next = newNode;
}
}
插入方法
public void Insert(T item, int index)
{
Node<T> newNode = new Node<T>(item);
if (index == 0) //插入到头结点
{
newNode.Next = head;
head = newNode;
}
else //中途插入
{
Node<T> temp = head;
for (int i = 1; i <= index-1; i++)
{
//让temp向后移动一个位置
temp = temp.Next;
}
Node<T> preNode = temp;
Node<T> nextNode = temp.Next;
preNode.Next = newNode;
newNode.Next = nextNode;
}
}
删除方法
public T Delete(int index)
{
T data = default(T);
if (index == 0)
{
data = head.Data;
head = head.Next;
}
else
{
Node<T> temp = head;
for (int i = 1; i <= index - 1; i++)
{
temp = temp.Next;
}
Node<T> preNode = temp;
Node<T> currentNode = temp.Next;
data = currentNode.Data;
Node<T> nextNode = temp.Next.Next;
preNode.Next = nextNode;
}
return data;
}