简单数据结构(一)线性表

最简单的结构:线性表

先进先出的结构:队列

先进后出的结构:栈

线性表

线性表数据结构具有以下特征:
  有且只有一个“首元素”
  有且只有一个“末元素”
  除末元素之外,其余元素均有惟一的后继元素
  除首元素之外,其余元素均有惟一的前驱元素
对于线性表,主要可进行以下操作:
  添加结点
  插入结点
  删除结点
  查找结点
  遍历结点
  统计结点数

其中线性表也分为:顺序表 and 链表



顺序表:在计算机内,保存线性表最简单、最自然的方式,就是把表中的元素一个接一个地放进顺序的存储单元,这就是线性表的顺序存储(Sequence Storage)。线性表的顺序存储是指在内存中用一块地址连续的空间依次存放线性表的数据元素,用这种方式存储的线性表叫顺序表(Sequence List),如图所示。顺序表的特点是表中相邻的数据元素在内存中存储位置也相邻。

 

程序自己实现线性表:

  线性表的接口定义:

public interface IListDS<T>
    {
       int GetLength(); //求长度
        void Clear(); //清空操作
        bool IsEmpty(); //判断线性表是否为空
        void Add(T item); //附加操作
        void Insert(T item, int i); //插入操作
        T Delete(int i); //删除操作
        T GetElem(int i); //取表元
        T this[int index] { get; }//定义一个索引器 获取元素
        int Locate(T value); //按值查找
    }

顺序表:

class SeqList<T>:IListDS<T>
    {
        private T[] data;//用来存储数据
         private int count = 0;//表示存了多少个数据

         public SeqList(int size) //size就是最大容量
        {
            data = new T[size];
            count = 0;
        }
        public SeqList() : this(10) //默认构造函数 容量是10
        {

        }
        /// <summary>
        /// 取得数据的个数
        /// </summary>
        /// <returns></returns>
        public int GetLength()
        {
            return count;
        }
        public void Clear()
        {
            count = 0;
        }
        public bool isEmpty()
        {
            return count == 0;
        }
        public void Add(T item)
        {
            if (count==data.Length)//当前数组存满
            {
                Console.WriteLine("当前顺序表已存满,不允许再存入");
            }
            else
            {
                data[count] = item;
                count++;
            }
        }
        public void Insert(T item, int index)
        {
            for (int i = count-1; i >= index; i--)
            {
                data[i + 1] = data[i];
            }
            data[index] = item;
            count++;
        }
        public T Delete(int index)
        {
            T temp = data[index];
            for (int i = index+1; i < count; i++)
            {
                data[i - 1] = data[i];
            }
            count--;
            return temp;
        }
        public T this[int index]
        {
            get { return GetEle(index); }
        }
        public T GetEle(int index)
        {
            if (index>=0  && index<=count-1)//索引存在
            {
                return data[index];
            }
            else
            {
                Console.WriteLine("索引不存在");
                return default(T);//返回一个T类型的默认值
            }
        }
        public int Locate(T value)
        {
            for (int i = 0; i < count; i++)
            {
                if (data[i].Equals(value))
                {
                    return i;
                }
            }
            return -1;
        }
    }

操作顺序表:

SeqList<string> seqList=new SeqList<string>(); //使用自己写的顺序表           

            seqList.Add("123"); //往表中添加元素
            seqList.Add("456");
            seqList.Add("789");

            Console.WriteLine(seqList.GetEle(0));//取表元
            Console.WriteLine(seqList[0]);//自身 0号 位置元素
            seqList.Insert("777",1);//在 1号 位置插入

            for (int i = 0; i < seqList.GetLength(); i++)
            {
                Console.Write(seqList[i]+" ");
            }
            Console.WriteLine();
            seqList.Delete(0);//删除 0号 位置元素

            for (int i = 0; i < seqList.GetLength(); i++)
            {
                Console.Write(seqList[i] + " ");
            }
            Console.WriteLine();
            seqList.Clear();//清空该表
            Console.WriteLine(seqList.GetLength());

            Console.ReadKey();

结果:



链表:顺序表是用地址连续的存储单元顺序存储线性表中的各个数据元素,逻辑上相邻的数据元素在物理位置上也相邻。因此,在顺序表中查找任何一个位置上的数据元素非常方便,这是顺序存储的优点。但是,在对顺序表进行插入和删除时,需要通过移动数据元素来实现,影响了运行效率。线性表的另外一种存储结构——链式存储(Linked Storage),这样的线性表叫链表(Linked List)。链表不要求逻辑上相邻的数据元素在物理存储位置上也相邻,因此,在对链表进行插入和删除时不需要移动数据元素,但同时也失去了顺序表可随机存储的优点。

链表分为:单链表 双向链表 循环链表

单链表的存储:

链表是用一组任意的存储单元来存储线性表中的数据元素(这组存储单元可以是连续的,也可以是不连续的)。那么,怎么表示两个数据元素逻辑上的相邻关系呢?即如何表示数据元素之间的线性关系呢?为此,在存储数据元素时,除了存储数据元素本身的信息外,还要存储与它相邻的数据元素的存储地址信息。这两部分信息组成该数据元素的存储映像(Image),称为结点(Node)。把存储据元素本身信息的域叫结点的数据域(Data Domain),把存储与它相邻的数据元素的存储地址信息的域叫结点的引用域(Reference Domain)。因此,线性表通过每个结点的引用域形成了一根“链条”,这就是“链表”名称的由来。

如果结点的引用域只存储该结点直接后继结点的存储地址,则该链表叫单链表(Singly Linked List)。把该引用域叫 next。单链表结点的结构如图所示,图中 data 表示结点的数据域。

 

链式存储结构:

下图是线性表(a1,a2,a3,a4,a5,a6)对应的链式存储结构示意图

另外一种表示形式:

 

单链表节点定义:

class Node<T>
    {
        private T data;//数据域 存储数据
        private Node<T> next;//引用域 指针 用来指向下一个元素 

        //构造器
        public Node()
        {
            data = default(T);
            next = null;
        }
        //构造器
        public Node(T value)
        {
            data = value;
            next = null;
        }
        //构造器
        public Node(T value, Node<T> next)
        {
            this.data = value;
            this.next = next;
        }
        //构造器
        public Node(Node<T> next)
        {
            this.next = next;
        }
        //数据域属性
        public T Data
        {
            get { return data; }
            set { data = value; }
        }
        //引用域属性
        public Node<T> Next
        {
            get { return next; }
            set { next = value; }
        }
    }

单链表实现:

class LinkList<T>:IListDS<T>
    {
        private Node<T> head;//存储一个头结点

        //构造器
        public LinkList()
        {
            head = null;
        }
        //单链表的长度
        public int GetLength()
        {
            if (head == null) return 0;
            Node<T> temp = head;
            int count = 1;
            while (true)
            {
                if (temp.Next!=null)
                {
                    count++;
                    temp = temp.Next;
                }
                else
                {
                    break;
                }
            }
            return count;
        }
        //清空单链表
        public void Clear()
        {
            head = null;
        }
        //判断单链表是否为空
        public bool isEmpty()
        {
            return head == null;
        }
        //在单链表的末尾添加新元素
        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;
            }
        }
        //在单链表的第index个结点的位置前插入一个值为item的结点
        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> currentNode = temp.Next;
                preNode.Next = newNode;
                newNode.Next = currentNode;
            }
        }
        //删除单链表的第i个结点
        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 = 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;
        }
        public T this[int index]
        {
            get
            {
                Node<T> temp = head;
                for (int i = 1; i <= index; i++)
                {
                    //让temp向后移动一个位置
                    temp = temp.Next;
                }
                return temp.Data;
            }
        }
        //获得单链表的第i个数据元素
        public T GetEle(int index)
        {
            return this[index];
        }
        //在单链表中查找值为value的结点
        public int Locate(T value)
        {
            Node<T> temp = head;
            if (temp==null)
            {
                return -1;
            }
            else
            {
                int index = 0;
                while (true)
                {
                    if (temp.Data.Equals(value))
                    {
                        return index;
                    }
                    else
                    {
                        if (temp.Next != null)
                        {
                            temp = temp.Next;
                        }
                        else
                        {
                            break;
                        }
                    }
                }
                return -1;
            }
        }
    }

操作单链表:

LinkList<string> seqList=new LinkList<string>();

            seqList.Add("123");
            seqList.Add("456");
            seqList.Add("789");

            Console.WriteLine(seqList.GetEle(0));//操作结果一
            Console.WriteLine(seqList[0]);//操作结果二
            seqList.Insert("777",1);

            for (int i = 0; i < seqList.GetLength(); i++)
            {
                Console.Write(seqList[i] + " ");//操作结果三
            }
            Console.WriteLine();
            seqList.Delete(0);

            for (int i = 0; i < seqList.GetLength(); i++)
            {
                Console.Write(seqList[i] + " ");//操作结果四
            }
            Console.WriteLine();
            Console.WriteLine(seqList.Locate("789"));//操作结果五
            seqList.Clear();
            Console.WriteLine(seqList.GetLength());//操作结果六

            Console.ReadKey();

结果:



再来简单了解一下其他两种链表

双向链表

前面介绍的单链表允许从一个结点直接访问它的后继结点,所以, 找直接后继结点的时间复杂度是 O(1)。但是,要找某个结点的直接前驱结点,只能从表的头引用开始遍历各结点。如果某个结点的 Next 等于该结点,那么,这个结点就是该结点的直接前驱结点。也就是说,找直接前驱结点的时间复杂度是 O(n), n是单链表的长度。当然,我们也可以在结点的引用域中保存直接前驱结点的地址而不是直接后继结点的地址。这样,找直接前驱结点的时间复杂度只有 O(1),但找直接后继结点的时间复杂度是 O(n)。如果希望找直接前驱结点和直接后继结点的时间复杂度都是 O(1),那么,需要在结点中设两个引用域,一个保存直接前驱结点的地址,叫 prev,一个直接后继结点的地址,叫 next,这样的链表就是双向链表(Doubly Linked List)。双向链表的结点结构示意图如图所示。

双向链表插入示意图



循环链表

有些应用不需要链表中有明显的头尾结点。在这种情况下,可能需要方便地从最后一个结点访问到第一个结点。此时,最后一个结点的引用域不是空引用,而是保存的第一个结点的地址(如果该链表带结点,则保存的是头结点的地址),也就是头引用的值。带头结点的循环链表(Circular Linked List)如图所示。

 

我们可以根据自己的实际需要来选择相应的链表。

时间: 2024-09-29 01:04:07

简单数据结构(一)线性表的相关文章

软考之路--数据结构之线性表

数据就是数值,也就是我们通过观察.实验或计算得出的结果.数据有很多种,最简单的就是数字.数据也可以是文字.图像.声音等.数据可以用于科学研究.设计.查证等.结构,组成整体的各部分的搭配和安排,两者完美结合在一起,我们这样需要重新认识她,对她重新审视与定义:数据结构是程序设计的重要理论和技术基础,她所讨论的内容和技术,对从事软件项目的开发有重要作用,通过学习数据结构,我们学会从问题出发,分析和研究计算机加工的数据的特性,以便为应用所设计的数据悬着适当的逻辑结构.存储结构及其相应的操作方法,为提高应

数据结构之线性表(顺序存储结构)

小学生放学都是要按顺序排队的,一个接一个,每个小学生的前后位置是固定的,这样便于迅速清点. 其实这就是一个线性表,从这件事里我们就可以找到很多关于线性表的特性,如 1.线性表是一个序列,它是有顺序的(排队) 2.第一个元素无前驱,最后一个无后继,其他每个元素都有一个前驱和后继(一个接一个) 3.元素是有限的(小学生的个数是有限的) 4.数据类型都相同(都是小学生在排队) 说明白线性表示什么,下面我们直接看线性表的实现 线性表的实现分顺序存储结构和链式存储结构 顺序存储结构: #define LI

数据结构:线性表之单链表

线性表(亦作顺序表)是最基本.最简单.也是最常用的一种数据结构.线性表中数据元素之间的关系是一对一的关系,即除了第一个和最后一个数据元素之外,其它数据元素都是首尾相接的.线性表有两种存储结构: ①顺序存储结构,即存储单元在一段连续的地址上存储,常见的数组就是顺序存储结构的线性表: ②链式存储结构,即存储单元在不连续的地址上存储.因为其不连续性,除了要存数据元素信息(数据域)外,还要存储它后继元素(结点)的地址(指针域,链).学习链式结构最好将结点结构牢记于心,如下图: 链表的每个结点只含有一个指

自学数据结构——顺序线性表

胡乱写了一些代码 /* ============================================================================ Name : sqlist.c Author :codecup Version : Copyright : Your copyright notice Description : Hello World in C, Ansi-style ==========================================

[笔记]python数据结构之线性表:linkedlist链表,stack栈,queue队列

python数据结构之线性表 python内置了很多高级数据结构,list,dict,tuple,string,set等,在使用的时候十分舒心.但是,如果从一个初学者的角度利用python学习数据结构时,这些高级的数据结构可能给我们以迷惑. 比如,使用list实现queue的时候,入队操作append()时间复杂度可以认为是O(1),但是,出队操作pop(0)的时间复杂度就是O(n). 如果是想利用python学学数据结构的话,我觉得还是自己实现一遍基本的数据结构为好. 1.链表 在这里,我想使

自学数据结构——顺序线性表2

1 /* 2 ============================================================================ 3 Name : sqlist.c 4 Author : codecup 5 Version : 6 Copyright : Your copyright notice 7 Description : Hello World in C, Ansi-style 8 ==================================

数据结构:线性表插入一次删除一次的代码

#include <iostream> #include <cmath> #include <cstring> #include <algorithm> #include <stack> #include <queue> #include <cstdio> using namespace std; int insertsqlist(int weizhi,double charu,int *t,double b[]){   

Java数据结构(线性表--&gt;顺序表简单实现)

线性表是一种可以在任意位置插入和删除元素,由n个同类型元素组成的线性结构.主要包括顺序表,单链表,循环单链表,双向链表和仿真链表.应用比较广泛的是顺序表和单链表. 2 下面是线性表的接口,主要操作包括插入元素,删除元素,取得元素,得到线性表元素个数,判断线性表是否为空. 3 package com.linear.table; 4 /** 5 * 操作顺序表的接口方法 6 * @author Mature 7 * 8 */ 9 public interface MatureListInterfac

数据结构之线性表

线性表是最简单最常用的一种数据结构,在生活中各个方面都有应用. 线性表的定义:线性表大多数情况下是除了第一个位置的数据元素只存在后继元素,最后一个位置的数据元素只存在前驱元素外,所有数据元素都存在前驱和后继的一个有限序列.举个简单的例子就是:字母表中除了 a 只存在后继 b,z 只存在前驱 y之外,剩余的所有字母全部都有前驱和后继.为什么是大多数情况下,是因为线性表的链式存储结构中除了单向链表,还有循环链表和双向链表. 线性表的存储结构:顺序存储(数组实现,需要预先分配连续的内存空间)和链式存储

【数据结构】 线性表的顺序表

线性表是一种最为常用的数据结构,包括了一个数据的集合以及集合中各个数据之间的顺序关系.线性表从数据结构的分类上来说是一种顺序结构.在Python中的tuple,list等类型都属于线性表的一种. 从抽象数据类型的线性表来看,一个线性表应该具有以下这些操作(以伪代码的形式写出): ADT List: List(self) #表的构造操作,创建一个新表 is_empty(self) #判断一个表是不是空表 len(self) #返回表的长度 prepend(self,elem) #在表的开头加入一个