C#數(shù)據(jù)結(jié)構(gòu)

數(shù)據(jù)結(jié)構(gòu)

數(shù)據(jù)結(jié)構(gòu)分類(DataStructure)

  • 數(shù)據(jù)結(jié)構(gòu)是相互之間存在一種或多種特定關(guān)系的數(shù)據(jù)元素的集合。
  • 在任何問題中,數(shù)據(jù)元素之間不是孤立的,而是存在一定關(guān)系,這種關(guān)系稱為結(jié)構(gòu)(structure)。

根據(jù)數(shù)據(jù)元素之間關(guān)系的不同特性,可分為4種基本數(shù)據(jù)結(jié)構(gòu):

  • 集合(set)集合中的數(shù)據(jù)元素除了存在“同屬于一個(gè)集合”的關(guān)系外,不存在任何其他關(guān)系。
  • 線性結(jié)構(gòu)(linear structure)線性結(jié)構(gòu)中數(shù)據(jù)元素存在著一對(duì)一的關(guān)系
  • 樹形結(jié)構(gòu)(tree structure)樹形結(jié)構(gòu)中數(shù)據(jù)元素存在一對(duì)多的關(guān)系
  • 圖形結(jié)構(gòu)(graphic structure)圖形結(jié)構(gòu)中數(shù)據(jù)元素存在多對(duì)多的關(guān)系
基本數(shù)據(jù)結(jié)構(gòu)

算法

  • 算法可理解為基本運(yùn)算及規(guī)定的運(yùn)算順序所構(gòu)成的完整的解題步驟
  • 算法可視為按照要求設(shè)計(jì)好的有限的確切的計(jì)算序列,并按步驟和序列解決某類問題。

數(shù)據(jù)結(jié)構(gòu)和算法之間的關(guān)系

  • 數(shù)據(jù)結(jié)構(gòu)可認(rèn)為是數(shù)據(jù)在程序中的存儲(chǔ)結(jié)構(gòu)和基本數(shù)據(jù)操作
  • 算法是用來解決問題的,算法是基于數(shù)據(jù)結(jié)構(gòu)的。
  • 數(shù)據(jù)結(jié)構(gòu)是問題的核心,是算法的基礎(chǔ)。

算法的評(píng)價(jià)標(biāo)準(zhǔn)

  • 運(yùn)行時(shí)間(running time)
  • 占用空間(storage space)有時(shí)需要犧牲空間換取時(shí)間,有時(shí)需要犧牲時(shí)間換取空間。
  • 正確性(correctness)
  • 可讀性(readability)
  • 健壯性(robustness)

線性表

線性表是線性結(jié)構(gòu)的抽象(abstruct),其特點(diǎn)是結(jié)構(gòu)中的數(shù)據(jù)元素之間存在一對(duì)一的線性關(guān)系,這種一對(duì)一的關(guān)系指的是數(shù)據(jù)元素之間的位置關(guān)系。

  • 除第一個(gè)位置的數(shù)據(jù)元素外,其他數(shù)據(jù)元素位置的前面都只有一個(gè)數(shù)據(jù)元素。
  • 除最后一個(gè)位置的數(shù)據(jù)元素外,其他數(shù)據(jù)元素的后面都只有一個(gè)元素。

也就是說,數(shù)據(jù)元素是一個(gè)接著一個(gè)排列的。因此,可把線性表現(xiàn)象成一種數(shù)據(jù)元素序列的數(shù)據(jù)結(jié)構(gòu)。線性表就是位置有先后關(guān)系,一個(gè)接著一個(gè)排列的數(shù)據(jù)結(jié)構(gòu)。

CLR中的線性表

C#1.1提供了一個(gè)非泛型接口IList接口,IList接口中的項(xiàng)是object,實(shí)現(xiàn)了IList接口的子類有

  • ArrayList
  • ListDictionary
  • StringCollection
  • StringDictionary

C#2.0提供了泛型的IList<T>接口,實(shí)現(xiàn)IList<T>接口的類有List<T>。

List<string> list = new List<string>();
list.Add("alice");
list.Add("ben");
list.Add("carl");
Console.WriteLine(list[0]);//根據(jù)索引器訪問元素

list.Remove("ben");
Console.WriteLine(list.Count);

list.Clear();
Console.WriteLine(list.Count);

Console.ReadKey();

實(shí)現(xiàn)線性表接口定義

namespace DataStructure
{
    /// <summary>
    /// 線性表接口定義
    /// </summary>
    /// <typeparam name="T"></typeparam>
    interface IList<T>
    {
        /// <summary>
        /// 獲取線性表長度,即元素個(gè)數(shù)。
        /// </summary>
        /// <returns></returns>
        int Count();
        /// <summary>
        /// 清空線性表
        /// </summary>
        void Clear();
        /// <summary>
        /// 判斷線性表是否為空
        /// </summary>
        /// <returns></returns>
        bool IsEmpty();
        /// <summary>
        /// 線性表插入元素
        /// </summary>
        /// <param name="item">數(shù)據(jù)項(xiàng)</param>
        /// <param name="index">數(shù)據(jù)索引</param>
        void Insert(T item, int index);
        /// <summary>
        /// 線性表追加元素
        /// </summary>
        /// <param name="item">數(shù)據(jù)項(xiàng)</param>
        void Append(T item);
        /// <summary>
        /// 刪除線性表元素
        /// 根據(jù)索引刪除指定位置的元素
        /// </summary>
        /// <param name="index">元素位置索引</param>
        /// <returns></returns>
        T Delete(int index);
        /// <summary>
        /// 根據(jù)索引獲取線性表元素
        /// </summary>
        /// <param name="index">元素索引</param>
        /// <returns></returns>
        T Get(int index);
        /// <summary>
        /// 索引器
        /// 根據(jù)索引訪問元素
        /// </summary>
        /// <param name="index">元素索引</param>
        /// <returns></returns>
        T this[int index] { get; }
        /// <summary>
        /// 根據(jù)值獲取索引值
        /// </summary>
        /// <param name="value">元素值</param>
        /// <returns></returns>
        int Location(T value);
    }
}

線性表的實(shí)現(xiàn)方式

  • 順序表
  • 單鏈表
  • 雙向鏈表
  • 循環(huán)鏈表

順序表

計(jì)算機(jī)內(nèi)存中保存線性表最簡單自然的方式,是把線性表中的元素一個(gè)接著一個(gè)放入順序的存儲(chǔ)單元中,這就是線性表的順序存儲(chǔ)(sequence storage)。

線性表的順序存儲(chǔ)指的是在內(nèi)存中使用一塊地址連續(xù)的空間依次存放線性表的數(shù)據(jù)元素,使用這種方式存放的線性表叫做順序表(sequence list)。

順序表的特點(diǎn)是表中相鄰的數(shù)據(jù)元素在內(nèi)存中存儲(chǔ)的位置是相鄰的。

順序表

順序表的任意存儲(chǔ)

假設(shè):順序表中每個(gè)數(shù)據(jù)元素占用 w 個(gè)存儲(chǔ)單元,設(shè)第 i 個(gè)數(shù)據(jù)元素的存儲(chǔ)地址為 Loc(ai),則有

Loc(ai) = Loc(a1) + (i-1)*w

1<= i <= n式中的Loc(ai) 表示第1個(gè)數(shù)據(jù)元素 a1 的存儲(chǔ)地址,也就是順序表的起始存儲(chǔ)地址,成為順序表的基地址(base address)。

也就是說,只要知道順序表的基地址和每個(gè)數(shù)據(jù)元素所占的存儲(chǔ)單元的個(gè)數(shù),就可以求出順序表中任意一個(gè)數(shù)據(jù)元素的存儲(chǔ)地址。

由于計(jì)算順序表中每個(gè)數(shù)據(jù)元素存儲(chǔ)地址的時(shí)間是相同的,所以順序表具有任意存取的特定,即可以在任意位置存取數(shù)據(jù)。

C#中的數(shù)組在內(nèi)存中占用的存儲(chǔ)空間是一組連續(xù)的存儲(chǔ)區(qū)域。因此,數(shù)組具有任意存取的特點(diǎn)。所以,數(shù)組天生具有表示順序表的數(shù)據(jù)存儲(chǔ)區(qū)域的特性。

namespace DataStructure
{
    /// <summary>
    /// 順序表
    /// </summary>
    /// <typeparam name="T"></typeparam>
    class SequenceList<T> : IList<T>
    {
        /// <summary>
        /// 用于存取數(shù)據(jù)的數(shù)組
        /// </summary>
        private T[] data;
        /// <summary>
        /// 用于記錄存取元素的個(gè)數(shù)
        /// </summary>
        private int count = 0;

        /// <summary>
        /// 自定義構(gòu)造器
        /// 不提供自動(dòng)擴(kuò)容
        /// </summary>
        /// <param name="maxsize">元素最大個(gè)數(shù)</param>
        public SequenceList(int maxsize)
        {
            data = new T[maxsize];
            count = 0;
        }
        /// <summary>
        /// 默認(rèn)構(gòu)造器
        /// 默認(rèn)容量為10
        /// </summary>
        public SequenceList():this(10)
        {
        }
        /// <summary>
        /// 索引器
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public T this[int index]
        {
            get
            {
                return Get(index);
            }
        }
        /// <summary>
        /// 追加元素
        /// </summary>
        /// <param name="item"></param>
        public void Append(T item)
        {
            //判斷數(shù)組是否飽和
            if(count == data.Length)
            {
                System.Console.WriteLine("當(dāng)前順序表已存滿,禁止存入數(shù)據(jù)。");
            }
            else
            {
                data[count] = item;
                count++;
            }
            //todo:返回當(dāng)前數(shù)組的索引
        }
        /// <summary>
        /// 清空數(shù)據(jù)
        /// </summary>
        public void Clear()
        {
            count = 0;
        }
        /// <summary>
        /// 獲取數(shù)據(jù)個(gè)數(shù)
        /// </summary>
        /// <returns>數(shù)據(jù)個(gè)數(shù)</returns>
        public int Count()
        {
            return count;
        }
        /// <summary>
        /// 根據(jù)索引刪除元素
        /// </summary>
        /// <param name="index"></param>
        public T Delete(int index)
        {
            T item = data[index];
            //把數(shù)據(jù)向前移動(dòng)
            for(int i = index+1;i<count; i++)
            {
                data[i - 1] = data[i];
            }
            count--;
            return item;
        }
        /// <summary>
        /// 根據(jù)索引獲取值
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public T Get(int index)
        {
            //判斷索引是否存在
            if(index >= 0 && index <= count - 1)
            {
                return data[index];
            }
            else
            {
                System.Console.WriteLine("當(dāng)前順序表中索引不存在");
                //返回T類型的默認(rèn)值
                return default(T);
            }
        }
        /// <summary>
        /// 插入元素
        /// </summary>
        /// <param name="item"></param>
        /// <param name="index"></param>
        public void Insert(T item, int index)
        {
            //從后向前
            for(int i = count - 1; i >= index; i--)
            {        
                data[i + 1] = data[i];
            }
            data[index] = item;
            count++;
        }

        /// <summary>
        /// 判斷是否為空
        /// </summary>
        /// <returns></returns>
        public bool IsEmpty()
        {
            return count == 0;
        }
        /// <summary>
        /// 根據(jù)值獲取索引
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public int Location(T value)
        {
            for(int i=0; i<count; i++)
            {
                if (data[i].Equals(value))
                {
                    return i;
                }
            }
            return -1;
        }
    }
}

順序表是用地址連續(xù)的存儲(chǔ)單元順序存儲(chǔ)線性表中的各個(gè)數(shù)據(jù)元素,邏輯上相鄰的數(shù)據(jù)元素在物理位置上也是相鄰的。

  • 優(yōu)點(diǎn):在順序表中查找任何一個(gè)位置上的數(shù)據(jù)元素快速高效,這是順序存儲(chǔ)的優(yōu)點(diǎn)。
  • 缺點(diǎn):在對(duì)順序表進(jìn)行插入和刪除時(shí),需通過移動(dòng)數(shù)據(jù)元素來實(shí)現(xiàn),影響運(yùn)行效率。
  • 特點(diǎn):存取快,插入刪除慢。

鏈表

線性表的另一種存儲(chǔ)結(jié)構(gòu) - 鏈?zhǔn)酱鎯?chǔ)(LinkedStorage),這種線性表叫做鏈表(LinkedList)。

鏈表不要求邏輯上相鄰的數(shù)據(jù)元素在物理存儲(chǔ)位置上也相鄰

  • 優(yōu)點(diǎn):在對(duì)鏈表進(jìn)行插入和刪除時(shí)無需移動(dòng)數(shù)據(jù)元素
  • 缺點(diǎn):鏈表因此失去了順序表可隨機(jī)存儲(chǔ)的優(yōu)勢(shì)
  • 特點(diǎn):插入刪除較快,查找較慢。

鏈表節(jié)點(diǎn)

鏈表是用一組任意的存儲(chǔ)單元來存儲(chǔ)線性表中的數(shù)據(jù)元素,這組存儲(chǔ)單元可以是連續(xù),有可以不是連續(xù)的。那么,如何表示兩個(gè)數(shù)據(jù)元素邏輯上是相鄰的關(guān)系呢?也就是說,如何表示數(shù)據(jù)元素之間的線性關(guān)系呢?

為此,在存儲(chǔ)數(shù)據(jù)元素時(shí),除了存儲(chǔ)數(shù)據(jù)本身的元信息外,還要存儲(chǔ)與它相鄰的數(shù)據(jù)元素的存儲(chǔ)地址。這兩部分信息組成該數(shù)據(jù)元素的存儲(chǔ)映像(image),稱之為節(jié)點(diǎn)(node)。

節(jié)點(diǎn)

我們把存儲(chǔ)數(shù)據(jù)元素本身的域稱為節(jié)點(diǎn)的數(shù)據(jù)域(data domain),把存儲(chǔ)與之相鄰的數(shù)據(jù)元素的存儲(chǔ)地址信息的域稱為節(jié)點(diǎn)的引用域(reference domain)。

因此,線性表通過每個(gè)節(jié)點(diǎn)的引用域形成了一根“鏈條”,這就是鏈表名稱的由來。

鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)
namespace DataStructure
{
    /// <summary>
    /// 鏈表節(jié)點(diǎn)
    /// </summary>
    /// <typeparam name="T"></typeparam>
    class Node<T>
    {
        /// <summary>
        /// 存儲(chǔ)的數(shù)據(jù)
        /// </summary>
        private T data;

        /// <summary>
        /// 指針
        /// 用于指向下一個(gè)元素
        /// </summary>
        private Node<T> next;

        /// <summary>
        /// 默認(rèn)構(gòu)造器
        /// </summary>
        public Node()
        {
            data = default(T);
            next = null;
        }
        public Node(T value)
        {
            data = value;
            next = null;
        }
        public Node(Node<T> next)
        {
            this.next = next;
        }
        public Node(T value, Node<T> next)
        {
            this.data = value;
            this.next = next;
        }
        /// <summary>
        /// 數(shù)據(jù) 存取器
        /// </summary>
        public T Data
        {
            get { return data; }
            set { data = value; }
        }
        /// <summary>
        /// 指針 存取器
        /// </summary>
        public Node<T> Next
        {
            get { return next; }
            set { next = value; }
        }
    }
}

單鏈表

順序表是用地址連續(xù)的存儲(chǔ)單元順序存儲(chǔ)線性表中的各個(gè)元素,邏輯上相鄰你的數(shù)據(jù)元素在物理位置上也相鄰。因此,在線性表中查找任何一個(gè)位置上的數(shù)據(jù)元素非常方便,這是順序表存儲(chǔ)的優(yōu)點(diǎn)。但是,在對(duì)順序表進(jìn)行插入和刪除時(shí),需要通過移動(dòng)數(shù)據(jù)元素來實(shí)現(xiàn),影響了運(yùn)行效率。

線性表的另一種存儲(chǔ)結(jié)構(gòu)-鏈?zhǔn)酱鎯?chǔ)(Linked Storage),這樣的線性表叫鏈表(Linked List)。鏈表不要求邏輯的數(shù)據(jù)元素在物理存儲(chǔ)位置上也相鄰。因此,在對(duì)鏈表進(jìn)行插入和刪除時(shí),無需移動(dòng)數(shù)據(jù)元素,但同時(shí)也失去了順序表可隨機(jī)存儲(chǔ)的優(yōu)點(diǎn)。

namespace DataStructure
{
    class SingleLinkedList<T> : IList<T>
    {
        /// <summary>
        /// 頭節(jié)點(diǎn)
        /// </summary>
        private Node<T> head;
        /// <summary>
        /// 構(gòu)造器
        /// </summary>
        public SingleLinkedList()
        {
            head = null;
        }
        /// <summary>
        /// 索引器
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public T this[int index]
        {
            get
            {
                Node<T> node = head;
                //獲取當(dāng)前節(jié)點(diǎn)
                for (int i = 0; i <= index; i++)
                {
                    node = node.Next;
                }
                return node.Data;
            }
        }
        /// <summary>
        /// 單鏈表添加新節(jié)點(diǎn)
        /// </summary>
        /// <param name="item"></param>
        public void Append(T item)
        {
            //創(chuàng)建新節(jié)點(diǎn)
            Node<T> node = new Node<T>(item);
            //判斷頭節(jié)點(diǎn)
            if(head == null)
            {
                head = node;
            }
            else
            {
                //追加至尾節(jié)點(diǎn)
                Node<T> tmp = head;
                //獲取尾節(jié)點(diǎn)
                while (true)
                {
                    if (tmp.Next != null)
                    {
                        tmp = tmp.Next;
                    }
                    else
                    {
                        break;
                    }
                }
                //將新節(jié)點(diǎn)放入鏈表尾部
                tmp.Next = node;
            }
        }
        /// <summary>
        /// 清空單鏈表
        /// </summary>
        public void Clear()
        {
            head = null;
        }
        /// <summary>
        /// 獲取單鏈表長度
        /// </summary>
        /// <returns></returns>
        public int Count()
        {
            //判斷頭節(jié)點(diǎn)是否為空
            if (head == null)
            {
                return 0;
            }

            int count = 1;
            Node<T> tmp = head;
            while (true)
            {
                //若當(dāng)前節(jié)點(diǎn)存在下一個(gè)節(jié)點(diǎn)則長度自增1
                if (tmp.Next != null)
                {
                    count++;
                    tmp = tmp.Next;
                }
                else
                {
                    break;
                }
            }
            return count;
        }
        /// <summary>
        /// 根據(jù)索引刪除單鏈表元素
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public T Delete(int index)
        {
            T data = default(T);
            //判斷是否為頭節(jié)點(diǎn)
            if(index == 0)
            {
                data = head.Data;
                head = head.Next;
            }
            else
            {
                Node<T> tmp = head;
                //獲取當(dāng)前節(jié)點(diǎn)的上一個(gè)節(jié)點(diǎn)
                for(int i=1; i<=index - 1; i++)
                {
                    tmp = tmp.Next;    
                }
                Node<T> prevNode = tmp;
                //獲取當(dāng)前節(jié)點(diǎn)的數(shù)據(jù)
                Node<T> currNode = tmp.Next;
                data = currNode.Data;
                //獲取當(dāng)前節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)
                Node<T> nextNode = tmp.Next.Next;
                //刪除當(dāng)前節(jié)點(diǎn)
                prevNode.Next = nextNode;
            }
            return data;
        }
        /// <summary>
        /// 根據(jù)指定索引獲取單鏈表數(shù)據(jù)
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public T Get(int index)
        {
            return this[index];
        }
        /// <summary>
        /// 指定位置插入新節(jié)點(diǎn)
        /// </summary>
        /// <param name="item"></param>
        /// <param name="index"></param>
        public void Insert(T item, int index)
        {
            //目標(biāo)節(jié)點(diǎn)
            Node<T> node = new Node<T>(item);
            //插入位置為頭節(jié)點(diǎn)
            if(index == 0)
            {
                node.Next = head;
                head = node;
            }
            else
            {
                //目標(biāo)節(jié)點(diǎn)的上一個(gè)節(jié)點(diǎn)
                Node<T> tmp = head;

                //臨時(shí)節(jié)點(diǎn)后移index-1個(gè)位置
                for (int i=1; i<=index - 1; i++)
                {
                    tmp = tmp.Next;
                }
                Node<T> prevNode = tmp;

                //獲取目標(biāo)節(jié)點(diǎn)
                Node<T> currNode = tmp.Next;

                //插入新節(jié)點(diǎn)
                prevNode.Next = node;
                node.Next = currNode;
            }
        }
        /// <summary>
        /// 判斷單鏈表是否為空
        /// </summary>
        /// <returns></returns>
        public bool IsEmpty()
        {
            return head == null;
        }
        /// <summary>
        /// 根據(jù)數(shù)據(jù)獲取單鏈表的索引
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public int Location(T value)
        {
            Node<T> tmp = head;
            if(tmp == null)
            {
                return -1;
            }
            else
            {
                int index = 0;
                while (true)
                {
                    if (tmp.Data.Equals(value))
                    {
                        return index;
                    }
                    else
                    {
                        if(tmp.Next != null)
                        {
                            tmp = tmp.Next;
                        }
                        else
                        {
                            break;
                        }
                    }
                    index++; 
                }
                return -1;
            }
        }
    }
}

雙向鏈表

單鏈表允許從一個(gè)結(jié)點(diǎn)直接訪問它的后繼節(jié)點(diǎn),所以,查找后繼結(jié)點(diǎn)的時(shí)間復(fù)雜度是O(1)。但是,要查找某個(gè)結(jié)點(diǎn)的直接前驅(qū)結(jié)點(diǎn),只能從表的頭引用開始遍歷各個(gè)結(jié)點(diǎn)。

如果某個(gè)結(jié)點(diǎn)的Next等于該結(jié)點(diǎn),那么,這個(gè)結(jié)點(diǎn)就是該結(jié)點(diǎn)的直接前驅(qū)結(jié)點(diǎn)。也就是說,查找直接前驅(qū)結(jié)點(diǎn)的時(shí)間復(fù)雜度是O(n),n是單鏈表的長度。當(dāng)然,我們也可以在結(jié)點(diǎn)的引用域內(nèi)保存直接前驅(qū)結(jié)點(diǎn)的地址而非直接后繼節(jié)點(diǎn)的地址。這樣,查找直接前驅(qū)結(jié)點(diǎn)的時(shí)間復(fù)雜度只有O(1),但查找后繼節(jié)點(diǎn)的時(shí)間復(fù)雜度是O(n)。

如果希望查找直接前驅(qū)結(jié)點(diǎn)和直接后繼節(jié)點(diǎn)的時(shí)間復(fù)雜度都是O(1),那么,需要在結(jié)點(diǎn)中設(shè)置兩個(gè)引用域,一個(gè)保存直接前驅(qū)結(jié)點(diǎn)的地址叫做prev,一個(gè)直接后繼節(jié)點(diǎn)的地址叫做next,這樣的鏈表就是雙向鏈表Doubly Linked List。

雙向鏈表的節(jié)點(diǎn)結(jié)構(gòu)
雙向鏈表的插入操作

循環(huán)鏈表

某些應(yīng)用不需要鏈表中有明顯的頭尾結(jié)點(diǎn),在這種情況下,可能需要方便地從最后一個(gè)節(jié)點(diǎn)訪問到第一個(gè)節(jié)點(diǎn)。此時(shí),最后一個(gè)節(jié)點(diǎn)的引用域不是空引用,而是保存第一個(gè)結(jié)點(diǎn)的地址,如果該鏈表帶結(jié)點(diǎn)則保存的是頭結(jié)點(diǎn)的地址,也就是頭引用的值。

帶頭結(jié)點(diǎn)的循環(huán)鏈表(Circular Linked List)

帶頭結(jié)點(diǎn)的循環(huán)鏈表

棧和隊(duì)列

棧和隊(duì)列是非常重要的兩種數(shù)據(jù)結(jié)構(gòu),在軟件設(shè)計(jì)中應(yīng)用很多。棧和隊(duì)列也是線性結(jié)構(gòu),線性表、棧、隊(duì)列這三種數(shù)據(jù)結(jié)構(gòu)的數(shù)據(jù)元素以及數(shù)據(jù)元素間的邏輯關(guān)系完全相同。差別在于線性表的操作不受限制,而棧和隊(duì)列的操作受到限制。棧的操作只能在表的一端進(jìn)行,隊(duì)列的插入操作在表的一端進(jìn)行而且其它操作在表的另一端進(jìn)行。所以,把棧和隊(duì)列稱為操作受限的線性表

棧(stack)是操作限定在表的尾端進(jìn)行的線性表,表尾由于要進(jìn)行插入、刪除等操作。所以,它具有特殊的含義,把表尾稱為棧頂(Top),另一端是固定的,叫做棧底(Bottom)。當(dāng)棧中沒有數(shù)據(jù)元素時(shí)叫做空棧(Empty Stack)。

棧通常標(biāo)記為:S = (a1, a2,... an),S是英文單詞Stack的第一個(gè)字母。a1為棧底元素,an為棧頂元素。這n個(gè)數(shù)據(jù)元素按照a1, a2...an的順序依次入棧,而出棧的次序相反。an第一個(gè)出棧,a1最后一個(gè)出棧。所以,棧的操作是按照后進(jìn)先出(LIFO, Last In First Out)或先進(jìn)后出(FILO, First In Last Out)的原則進(jìn)行的。因此,棧又稱為LIFO表或FILO表。

棧的操作示意圖

棧的操作示意圖
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 線性表是數(shù)據(jù)結(jié)構(gòu)中最簡單的基本數(shù)據(jù)結(jié)構(gòu)。線性表的使用和維護(hù)都很簡單,這一特點(diǎn)使其成為很多算法的基礎(chǔ)。數(shù)組、鏈表、棧...
    JunChow520閱讀 1,442評(píng)論 1 4
  • 數(shù)據(jù)結(jié)構(gòu)是相互之間存在一種或多種特定關(guān)系的數(shù)據(jù)元素的集合。 算法為有基本運(yùn)算及規(guī)定的運(yùn)算順序所構(gòu)成的完整的解題步驟...
    銀河的精神家園閱讀 765評(píng)論 0 0
  • 關(guān)于Mongodb的全面總結(jié) MongoDB的內(nèi)部構(gòu)造《MongoDB The Definitive Guide》...
    中v中閱讀 32,329評(píng)論 2 89
  • 為了誰,為了美好的明天; 為了誰,為了夢(mèng)想變成真; 為了誰,為了汗水結(jié)碩果; 為了誰,為了寒冬終無悔! 我愿裊裊春...
    傾心閱齋閱讀 347評(píng)論 1 5
  • 1,一開始被逼著來,有點(diǎn)點(diǎn)抵觸,經(jīng)過一年多的時(shí)間發(fā)現(xiàn)自己很多不足,不自律,很多壞毛病。想改變現(xiàn)狀,所有重新參加參加...
    萬眾檢測(cè)申威閱讀 158評(píng)論 0 0

友情鏈接更多精彩內(nèi)容