一、線性表的邏輯結構
- 線性表的定義
1) 線性表(List)是由 n(n≥0)個相同類型的資料元素構成的有限序列。
2) 線性表的形式化定義為:線性表(List)簡記為L,是一個二元組,
L = (D, R)
其中:D是資料元素的有限集合。
R是資料元素之間關係的有限集合。
在實際生活中線性表的例子很多。例如,1 到 100 的偶數就是一個線性表: (2,4,6,…,100)
3) 在一個複雜的線性表中,一個資料元素是一個記錄,由若干個資料項目組成,
含有大量記錄的線性表又稱檔案(File)。例如,例子 1.1 中的學生資訊表就是一個線性表,表中的每一行是一個記錄。一個記錄由學號、姓名、行政班級、性別和出生年月等資料項目組成。
4) 在選擇線性表的標記法之前,程式設計人員首先應該考慮這種標記法要支援
的基本操作。從線性表的定義可知,一個線性表在長度上應該能夠增長和縮短,
也就是說,線性表最重要的操作應該能夠線上性表的任何位置插入和刪除元素。除此之外,應該可以有辦法獲得元素的值、讀出這個值或者修改這個值。也應該可以產生和清除(或者重新初始化)線性表。
- 順序表的定義
1) 線性表的順序儲存是指在記憶體中用一塊地址連續的空間依次存放線性表的資料元素,用這種方式儲存的線性表叫順序表(Sequence List)
2) C#語言中的數組在記憶體中佔用的儲存空間就是一組連續的儲存地區,因此,
數組具有隨機存取的特點。所以,數組天生具有表示順序表的資料存放區地區的特性。
3) 對數組採用轉置演算法:
class Program
{
static voidMain(string[]args)
{
int[]aa = new int[]{ 1, 2, 4, 5,7,8,9 };
Revose(aa);
for(int i = 0; i < aa.Length; i++)
{
Console.WriteLine(aa[i]);
}
}
public staticint[] Revose(int[] bb)
{
int temp = 0;
int len = bb.Length;
for (inti = 0; i < (bb.Length)/2; i++)
{
temp = bb[i];
bb[i]=bb[len-i-1];
bb[len-i-1]=temp;
}
return bb;
}
}
4)自訂順序表示例代碼:
using System;
using System.Collections.Generic;
using System.Text;
class Program
{
static void Main(string[] args)
{
SeqList<int> aa = new SeqList<int>(10);
aa.Append(11);
aa.Append(20);
aa.Append(220);
Console.WriteLine("未反轉結果");
for (int i = 0; i < aa.Last + 1; i++)
{
Console.WriteLine(aa[i]);
}
aa.Reverse();
Console.WriteLine("反轉後結果");
for (int i = 0; i < aa.Last+1; i++)
{
Console.WriteLine(aa[i]);
}
Console.WriteLine("尋找20的位置");
Console.WriteLine(aa.Locate(20));
Console.WriteLine("是否為空白");
Console.WriteLine(aa.IsEmpty());
Console.WriteLine("取第一個資料");
Console.WriteLine(aa.GetElem(1));
Console.WriteLine("刪除第一個資料");
aa.Delete(1);
Console.WriteLine("刪除後資料");
for (int i = 0; i < aa.Last + 1; i++)
{
Console.WriteLine(aa[i]);
}
}
}
public interface IListDS<T>
{
int GetLength(); //求長度
void Clear(); //清空操作
bool IsEmpty(); //判斷線性表是否為空白
void Append(T item); //附加操作
void Insert(T item, int i); //插入操作
T Delete(int i); //刪除操作
T GetElem(int i); //取表元
int Locate(T value); //按值尋找
}
public class SeqList<T> : IListDS<T>
{
private int maxsize; //順序表的容量
private T[] data; //數組,用於儲存順序表中的資料元素
private int last; //指示順序表最後一個元素的位置
//索引器
public T this[int index]
{
get
{
return data[index];
}
set
{
data[index] = value;
}
}
//最後一個資料元素位置屬性
public int Last
{
get
{
return last;
}
}
//容量屬性
public int Maxsize
{
get
{
return maxsize;
}
set
{
maxsize = value;
}
}
//構造器
public SeqList(int size)
{
data = new T[size];
maxsize = size;
last = -1;
}
//求順序表的長度
public int GetLength()
{
return last+1;
}
//清空順序表
public void Clear()
{
last = -1;
}
//判斷順序表是否為空白
public bool IsEmpty()
{
if (last == -1)
{
return true;
}
else
{
return false;
}
}
//判斷順序表是否為滿
public bool IsFull()
{
if (last == maxsize-1)
{
return true;
}
else
{
return false;
}
}
//在順序表的末尾添加新元素
public void Append(T item)
{
if(IsFull())
{
Console.WriteLine("List is full");
return;
}
data[++last] = item;
}
//在順序表的第i個資料元素的位置插入一個資料元素
public void Insert(T item, int i)
{
if (IsFull())
{
Console.WriteLine("List is full");
return;
}
if(i<1 || i>last+2)
{
Console.WriteLine("Position is error!");
return;
}
if (i == last + 2)
{
data[last+1] = item;
}
else
{
for (int j = last; j>= i-1; --j)
{
data[j + 1] = data[j];
}
data[i-1] = item;
}
++last;
}
//刪除順序表的第i個資料元素
public T Delete(int i)
{
T tmp = default(T);
if (IsEmpty())
{
Console.WriteLine("List is empty");
return tmp;
}
if (i < 1 || i > last+1)
{
Console.WriteLine("Position is error!");
return tmp;
}
if (i == last+1)
{
tmp = data[last--];
}
else
{
tmp = data[i-1];
for (int j = i; j <= last; ++j)
{
data[j] = data[j + 1];
}
}
--last;
return tmp;
}
//獲得順序表的第i個資料元素
public T GetElem(int i)
{
if (IsEmpty() || (i<1) || (i>last+1))
{
Console.WriteLine("List is empty or Position is error!");
return default(T);
}
return data[i-1];
}
//在順序表中尋找值為value的資料元素
public int Locate(T value)
{
if(IsEmpty())
{
Console.WriteLine("List is Empty!");
return -1;
}
int i = 0;
for (i = 0; i <= last; ++i)
{
if (value.Equals(data[i]))
{
break;
}
}
if (i > last)
{
return -1;
}
return i;
}
public void Reverse()
{
T tmp = default(T);
int len = GetLength();
for (int i = 0; i <= len / 2; ++i)
{
tmp = data[i];
data[i] = data[len - i-1];
data[len - i-1] = tmp;
}
}
}
- 單鏈表
1) 順序表是用地址連續的儲存單元順序儲存線性表中的各個資料元素,邏輯上
相鄰的資料元素在物理位置上也相鄰。因此,在順序表中尋找任何一個位置上的
資料元素非常方便,這是順序儲存的優點。但是,在對順序表進行插入和刪除時,
需要通過移動資料元素來實現,影響了運行效率。本節介紹線性表的另外一種存
儲結構——鏈式儲存(Linked Storage),這樣的線性表叫鏈表(Linked List)。鏈表不
要求邏輯上相鄰的資料元素在實體儲存體位置上也相鄰,因此,在對鏈表進行插入
和刪除時不需要移動資料元素,但同時也失去了順序表可隨機儲存的優點。
2) 鏈表是用一組任意的儲存單元來儲存線性表中的資料元素(這組儲存單元可
以是連續的,也可以是不連續的)。那麼,怎麼表示兩個資料元素邏輯上的相鄰
關係呢?即如何表示資料元素之間的線性關係呢?為此,在儲存資料元素時,除
了儲存資料元素本身的資訊外,還要儲存與它相鄰的資料元素的儲存地址資訊。
這兩部分資訊組成該資料元素的儲存映像(Image),稱為結點(Node)。把儲存據元
素本身資訊的域叫結點的資料域(Data Domain),把儲存與它相鄰的資料元素的存
儲地址資訊的域叫結點的參考網域(Reference Domain)。因此,線性表通過每個結
點的參考網域形成了一根“鏈條”,這就是“鏈表”名稱的由來。
- C#中的線性表
1) IList 介面表示一個集合,該集合中的項可被排序且可按索引任意訪問。
2) 非泛型的 IList 介面的聲明如下:
interface IList: ICollection,IEnumerable
{
//公有屬性
bool IsFixedSize{get;} //唯讀,如果IList有固定大小,
//其值為true,否則為 false。
bool IsReadOnly{get;} //唯讀,如果IList是唯讀,
//其值為true,否則為 false。
object this [Tindex] {get;set;} //索引器,得到或設定某個索引的項
//公有方法
int Add(object value); //添加某項到表中,返回被插入的新項
//在表中的位置。
void Clear(); //清空表。
int IndexOf(object value); //如果表中有與value 相等的項,
//返回其在表中的索引,否則,返回-1。
bool Contains(object value); //如果表中有與value 相等的項,
//返回true,否則為 false。
void Insert(int index,object value); //把值為value的項插入到索
//引為index的位置。
void Remove(object value); //刪除表中第一個值為value 的項。
void RemoveAt(int index); //刪除表中索引index處的項。
}
3) .NET架構中的一些集合類實現了 IList 介面,如ArrayList、ListDictionary、
StringCollection、StringDictionary。
4) ArrayList 類使用數組來實現 IList 介面,所以 ArrayList 可看作順序表。
ArrayList 的容量可動態增長,通常情況下,當 ArrayList 中的元素滿時,容量增加一倍,把原來的元素複製到新的空間中。當在 ArrayList 中插入一個元素時,該元素被添加到 ArrayList 的尾部,元素個數自動加 1。另外,需要注意的是,ArrayList中對元素的操作前提是 ArrayList 是一個有序表,但 ArrayList 本身並不一定是有序的。所以,在對 ArrayList 中的元素進行操作之前,應該對 ArrayList進行排序。關於排序的演算法見第7 章。
5) ArrayList的使用例子:
class Program
{
static voidMain(string[]args)
{
// 建立和初始化一個新的ArrayList.
ArrayList myAL = new ArrayList();
myAL.Add("Hello");
myAL.Add("World");
myAL.Add("!");
//顯示ArrayList 的屬性和值
Console.WriteLine("myAL");
Console.WriteLine("Count:{0}", myAL.Count);
Console.WriteLine("Capacity: {0}", myAL.Capacity);
Console.Write("Values:");
PrintValues(myAL);
}
public staticvoid PrintValues(IEnumerablemyList)
{
foreach(objectobj in myList)
{
Console.Write("{0}", obj);
Console.WriteLine();
}
}
}
6) 棧和隊列是電腦中常用的兩種資料結構,是操作受限的線性表。棧的插入
和刪除等操作都在棧頂進行,它是先進後出的線性表。隊列的刪除操作在隊頭進行,而插入、尋找等操作在隊尾進行,它是先進先出的線性表。與線性表一樣,棧和隊列有兩種儲存結構,順序儲存的棧稱為順序棧,鏈式儲存的棧稱為鏈棧。順序儲存的隊列稱為順序對列,鏈式儲存的隊列稱為鏈隊列。