線性表(順序表,連結串列等)及其實現(C#版)
線性表
線性表的實現方式有下面幾種
1.順序表
線性表的順序儲存是指在記憶體中用一塊地址連續的空間依次存放線性表的資料元素,用這種方式儲存的線性表叫順序表,它的實現主要依賴於陣列。
(1)空間上:
順序表的實現一般是實現連續開闢一段空間,然後在進行資料的增刪查改,所以當我們不知道要儲存多少資料時,用順序表來開闢的空間如果太大,就會造成一定程度上的浪費,
(2)時間上:
訪問隨機元素的時間複雜度:由於支援陣列下標訪問,所以順序表訪問隨機元素的時間複雜度是O(1)。
隨機位置插入、刪除元素的時間複雜度:
因為順序表的元素是連續儲存的,因此要在特定位置插入、刪除元素需要把它之後的元素全部後移或前移一個元素的位置,時間開銷比較大
順序表的實現:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _線性表
{
//IComparable<T>介面定義由值型別或類實現的特定於型別的通用比較方法,旨在對其例項進行排序。
public class SelfList<T> where T:IComparable
{
//T GetItem(int index);//獲取索引對應的值
//void Add(T item);//增添元素的方法
//void Insert(int index, T item); //插入元素的方法
//void RemoveAt(int index); // 移除對應指定索引處的元素。
//int IndexOf(T item);//搜尋指定的物件,並返回整個 System.Collections.Generic.List`1 中第一個匹配項的從零開始的索引。
//int LastIndexOf(T item); //搜尋指定的物件,第一個匹配項的從最後開始的索引。
//void Sort();//從小到大排序
int count;
T[] arry;
public int Count { get => count;}
public int Capacity{ get => arry.Length; }//容量,用於擴容
public SelfList(int size)
{
arry = new T[size];
}
public SelfList()
{
arry = new T[4];//沒有指定size時,預設為4
}
public T GetItem(int index)
{
if (index>=0&&index<Count)
{
return arry[index];
}
else
{
throw new Exception("索引超出範圍");
}
}
//通過索引器訪問
public T this[int index]
{
get
{
return GetItem(index);
}
set
{
if (index >= 0 && index < Count)
{
arry[index] = value;
}
else
{
throw new Exception("索引超出範圍");
}
}
}
public void Add(T item)
{
if (Count==Capacity)
{
T[] newarry = new T[Count * 2];
Array.Copy(arry, newarry, Count);
arry = newarry;
}
arry[Count] = item;
count++;
}
public void Insert(int index, T item)
{
if (index>=0&&index<=Count)//可以插入最後一位
{
if (Count == Capacity)
{
T[] newarry = new T[Count * 2];
Array.Copy(arry, newarry, Count);
arry = newarry;
}
for (int i = Count-1; i >= index; i--)
{
arry[i + 1] = arry[i];
}
arry[index] = item;
count++;
}
else
{
throw new Exception("索引超出範圍");
}
}
public int IndexOf(T item)
{
for (int i = 0; i < count; i++)
{
if (arry[i].Equals(item))
{
return i;
}
}
return -1;
}
public int LastIndexOf(T item)
{
for (int i = Count; i >=0; i--)
{
if (arry[i].Equals(item))
{
return i;
}
}
return -1;
}
public void RemoveAt(int index)
{
if (index >= 0 && index < Count)
{
for (int i = index; i < count-1; i++)
{
arry[i - 1] = arry[i];
}
count--;
}
else
{
throw new Exception("索引超出範圍");
}
}
// CompareTo(Object) 必須返回 Int32 具有以下三個值之一的,如下表所示。
//註解
//“值” 含義
//小於零 當前例項 CompareTo 在排序順序中位於方法所指定的物件之前。
//等於零 前例項與方法所指定的物件在排序順序中出現的位置相同 CompareTo 。
//大於零 此當前例項 CompareTo 在排序順序中跟隨方法所指定的物件之後。
public void Sort()
{
for (int i = 0; i < Count-1; i++)
{
for (int j = 0; j < Count-i-1; j++)
{
if (arry[j].CompareTo(arry[j+1])>0)
{
T tem = arry[j+1];
arry[j+1] = arry[j];
arry[j] = tem;
}
}
}
}
}
}
單鏈表
連結串列是用一組任意的儲存單元來儲存線性表中的資料元素(這組儲存單元可以是連續的,也可以是不連續的)。在儲存資料元素時,除了儲存資料元素本身的資訊外,還要儲存與它相鄰的資料元素的儲存地址資訊。這兩部分資訊組成該資料元素的儲存映像,稱為結點(Node)。把儲存據元素本身資訊的域叫結點的資料域,把儲存與它相鄰的資料元素的儲存地址資訊的域叫結點的引用域。
下圖是線性表(a1,a2,a3,a4,a5,a6)對應的鏈式儲存結構示意圖。
(1)空間上:
單鏈表則是一次只開闢一個結點的空間,用來儲存當前要儲存的資料及指向下一個結點或NULL的指標,但由於每次開闢的空間不是連續的,容易形成碎片空間,造成空間的浪費
(2)時間上:
**訪問隨機元素的時間複雜度:**單鏈表的資料是鏈式儲存的,它的元素是不支援隨機訪問的,想要知道某個元素,只能從頭結點開始遍歷整個連結串列,直到找到了該元素為止。
所以單鏈表訪問隨機元素的平均時間複雜度是O(n)。
隨機位置插入、刪除元素的時間複雜度:
單鏈表在插入或刪除元素時,只需要改變它的前驅節點及插入或刪除元素的指向即可,所以單鏈表在插入隨機位置插入、刪除元素的時間複雜度是O(1)。
鏈式表的實現
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _線性表
{
/// <summary>
/// 鏈式表(單向連結串列)
/// </summary>
class Chain<T> where T:IComparable
{
//T GetItem(int index);//獲取索引對應的值
//void Add(T item);//增添元素的方法
//void Insert(int index, T item); //插入元素的方法
//void RemoveAt(int index); // 移除對應指定索引處的元素。
//int IndexOf(T item);//搜尋指定的物件,並返回整個 System.Collections.Generic.List`1 中第一個匹配項的從零開始的索引。
//int LastIndexOf(T item); //搜尋指定的物件,第一個匹配項的從最後開始的索引。
//void Sort();//從小到大排序
int count;
Node<T> head;
public Chain()
{
head = null;
}
public int Count { get => count; }
public T GetItem(int index)
{
if (index >= 0 && index < Count)
{
Node<T> temp = head;
for (int i = 1; i <= index; i++)
{
temp = temp.next;
}
return temp.deta;
}
else
{
throw new Exception("索引超出範圍");
}
}
//通過索引器訪問
public T this[int index]
{
get
{
return GetItem(index);
}
set
{
if (index >= 0 && index < Count)
{
Node<T> temp = head;
for (int i = 0; i < index; i++)
{
temp = temp.next;
}
temp.deta = value;
}
else
{
throw new Exception("索引超出範圍");
}
}
}
public void Add(T item)
{
Node<T> newnode = new Node<T>(item);
if (head==null)
{//第一個節點為頭節點時
head = newnode;
}
else
{//第一個節點不是頭節點時,把新節點放在連結串列末尾
Node<T> temp = head;
while (temp.next!=null)
{
temp = head.next;
}
temp.next = newnode;
}
count++;
}
public void Insert(int index, T item)
{
Node<T> newnode = new Node<T>(item);
if (index == 0)
{//插入位置為第一個節點時
head= newnode;
newnode.next = head.next;
}
else
{//插入位置為不是第一個節點時,獲取插入位置的結點(currentNode)和插入位置前一個結點(preNode),
//使插入位置前一個結點(preNode)指向新節點(newNode),新節點(newNode)指向插入位置的結點(currentNode)
Node<T> temp = head;
for (int i = 1; i <= index-1; i++)
{
temp = temp.next;
}
Node<T> preNode = temp;
Node<T> currentNode = temp.next;
temp.next = newnode;
newnode.next = currentNode;
}
count++;
}
public int IndexOf(T item)
{
Node<T> temp = head;
int index = 0;
while (temp!=null)
{
if (temp.deta.Equals(item))
{
return index;
}
index++;
temp = temp.next;
}
return -1;
}
public int LastIndexOf(T item)
{
Node<T> temp = head;
int index = 0;
T[] array = new T[Count];
while (temp != null)
{
array[index++] = temp.deta;
temp = temp.next;
}
for (int i = index-1; i >=0; i++)
{
if (array[i].Equals(item))
{
return i;
}
}
return -1;
}
public void RemoveAt(int index)
{
if (index == 0)
{//移除位置為第一個節點時
head = head.next;
}
else
{//移除位置為不是第一個節點時,獲取移除位置前一個結點(preNode),移除位後置一個結點(nextNode)
//使移除位置前一個結點(preNode)指向移除位後置一個結點(nextNode)
Node<T> temp = head;
for (int i = 1; i <= index - 1; i++)
{
temp = temp.next;
}
Node<T> preNode = temp;
Node<T> nextNode = temp.next.next;
preNode.next = nextNode;
}
count--;
}
public void Sort()
{
//獲取所有節點位置
Node<T> temp = head;
Node<T>[] detas = new Node<T>[Count];
for (int i = 0; i < Count; i++)
{
detas[i] = temp;
temp = temp.next;
}
//氣泡排序
for (int i = 0; i < Count - 1; i++)
{
for (int j = 0; j < Count - i - 1; j++)
{
if (detas[j].deta.CompareTo(detas[j+1].deta)>0)
{
T temdeta = detas[j].deta;
detas[j].deta = detas[j + 1].deta;
detas[j+1].deta = temdeta;
}
}
}
}
}
}