数据结构小结 1

来源:互联网 发布:linux socket句柄 取值 编辑:程序博客网 时间:2024/06/14 03:27

## 对几个常见的线性数据结构做一个简单的分析和自定义的实现

1.顺序表

按照顺序存储方式存储的线性表,在计算机的一组连续的存储单元中,因此在查找的时候由于地址连续性,cpu寻址时是按照顺序往下,这样在寻找时会非常迅速,这就导致了顺序存储方式的查找非常高效。同时,由于地址连续性,在中间删除或者增加一个节点时,会影响到后面节点在物理内存中的地址都要往前或往后移动,因此当插入或删除时效率较低,而且随操作影响的节点的数量越多,效率越低。这里用Java实现一个自定义的顺序表

package baseDataStructure;import java.util.Scanner;/** * 顺序表结构 * 即按照顺序存储方式的线性表类似数组 * 每个节点的长度相同,在物理内存中连续存在,一个整的空间存放顺序表 * 便于查询,增删效率低 */public class SequentialList {    static final int MAXLEN = 100;      //定义顺序表的最大长度    DataList[] listData = new DataList[MAXLEN+1]; //保存顺序表的结构数组    int ListLen; //顺序表已经存的节点的数量    /**     * 初始化为空表,将位置指向0,这样在写入时如果有数据会直接覆盖,而不用先将数据清空     * @param sequentialList     */    void init(SequentialList sequentialList){        sequentialList.ListLen=0;    }    /**     * 返回顺序表的节点数量     * @param sequentialList     * @return     */    int getListLength(SequentialList sequentialList){        return sequentialList.ListLen;    }    /**     * 插入节点     * @param sequentialList 顺序表     * @param n 插入的位置     * @param dataList 节点对象     * @return 1表示成功,0表示失败     */    int insertSequentialList(SequentialList sequentialList,int n,DataList dataList){        int i;        if (sequentialList.ListLen >= MAXLEN){            System.out.println("顺序表已满,无法插入节点");            return 0;        }else if (n<1||n>sequentialList.ListLen-1){            System.out.println("位置有误:当前指定位置没有存储元素,无法插入");            return 0;        }        for (i = sequentialList.ListLen; i >=n ; i--) {            //将插入位置后面的所有元素下标向后移动一位,空出插入位置节点            sequentialList.listData[i+1] = sequentialList.listData[i];        }        sequentialList.listData[n]=dataList;        sequentialList.ListLen++;        return 1;    }    /**     * 在顺序表末尾加上元素     * @param sequentialList     * @param dataList     * @return 1表示成功,0表示失败     */    int addSequentialList(SequentialList sequentialList,DataList dataList){        if (sequentialList.ListLen>=MAXLEN){            System.out.println("顺序表已满,无法插入节点");            return 0;        }        sequentialList.listData[++sequentialList.ListLen]=dataList;        return 1;    }    /**     * 删除节点位置元素     * @param sequentialList     * @param n     * @return 1表示成功,0表示失败     */    int delSequentialList(SequentialList sequentialList,int n){        if (n<1||n>sequentialList.ListLen+1){            System.out.println("位置错误:删除节点的位置没有存有元素,无法删除");            return 0;        }        for (int i = n; i<sequentialList.ListLen ; i++) {            //将所有n位置后面的元素都向前挪动一位,然后删除最后一个            sequentialList.listData[i]=sequentialList.listData[i+1];        }        sequentialList.ListLen--;        return 1;    }    /**     * 通过下标位置查找元素     * @param sequentialList     * @param n     * @return     */    DataList findSequentialList(SequentialList sequentialList,int n){        if (n<1||n>sequentialList.ListLen+1){            System.out.println("位置错误:查找节点的位置没有存有元素,无法查询");            return null;        }else {            return sequentialList.listData[n];        }    }    /**     * 通过关键词(节点类里定义好的key)查询节点的位置返回下标     * @param sequentialList     * @param key     * @return 成功返回下标位置,失败返回0     */    int  findSequentialListByKey(SequentialList sequentialList,String key){        for (int i = 1; i <=sequentialList.ListLen ; i++) {            //compareTo 相等返回0,小于返回-1,大于返回1            if (sequentialList.listData[i].key.compareTo(key)==0){              return i;            }        }        return 0;    }    /**     * 显示当前顺序表所有节点内容     * @param sequentialList     */    void showAllSequentialList(SequentialList sequentialList){        for (int i = 1; i <=sequentialList.ListLen ; i++) {            System.out.println("第 "+i+" 个元素节点内容是\n"+sequentialList.listData[i].toString());        }    }    /**     * 使用实例     * @param args     */    public static void main(String[] args) {        SequentialList sequentialList = new SequentialList(); //定义顺序表        DataList dataList;  //定义节点引用的变量类型        String key;  //定义查询时的关键词        sequentialList.init(sequentialList); //初始化表        Scanner sc = new Scanner(System.in);        //循环添加节点内容        do {            System.out.println("请输入 关键词 姓名 年龄");            DataList tmpData = new DataList();            tmpData.key = sc.next();            tmpData.name = sc.next();            tmpData.age = sc.nextInt();            if (tmpData.age!=0){                if (sequentialList.addSequentialList(sequentialList,tmpData)==0){                    break;                }            }else {                break;            }        }while (true);        System.out.println("显示顺序表中的节点顺序");        sequentialList.showAllSequentialList(sequentialList);        System.out.println("要取出的节点号码为:");        int i = sc.nextInt();        dataList = sequentialList.findSequentialList(sequentialList,i);        if (dataList!=null){            System.out.println("第"+i+"个元素内容是"+dataList.toString());        }        System.out.println("输入关键词");        key = sc.next();        i = sequentialList.findSequentialListByKey(sequentialList,key);        dataList = sequentialList.findSequentialList(sequentialList,i);        if (dataList!=null){            System.out.println("关键词为"+key +"的元素内容是"+dataList.toString());        }    }}/** * 定义节点元素内容类,可以是一个任意的实体类 * 类似数组就是一个int 下标和一个Object value的实体类 */class DataList{    String key;  //节点关键词    String name;    int age;    @Override    public String toString() {        return "DataList{" +                "key='" + key + '\'' +                ", name='" + name + '\'' +                ", age=" + age +                '}';    }}

2.链表

链表结构是一种动态存储分配的结构形式,一般链表有两个部分,数据部分和地址部分。数据部分用于存储节点内的数据模型等,地址部分则保存下一个节点的地址。在定义链表时,需要定义一个头引用变量(head),这个head指向链表的第一个节点,第一个节点的地址部分指向第二个节点,直到最后一个节点的地址部分指向null 则表示链表完成。因此在物理内存中基本上都是非连续存在的,比如一个8G的内存区,第一个节点在3G的位置,第二个在7G的位置,而CPU需要挨个寻址,会导致查询的效率极低。(一般情况下不会出现,因为系统会给每个进程分配一定的空间 32位系统好像是在4G,前2G作为进程私有空间,后2G作为公用空间,同时在堆空间内,因此一般不会相距太远)但是在增删时只影响上一个节点的地址部分,而不用其他的节点内容,因此效率非常高。

package baseDataStructure;import java.util.Scanner;/** * 链表自定义 * 每个节点包括两个部分,数据部分和地址部分,地址部分指向下一个节点的地址 * 如果是双向链表,地址部分还包含指向上一个节点的地址 * 链表不同于顺序表,在物理内存中不连续 * 便于增删而不便于查找 */public class LinkList {    LinkListData nodeData = new LinkListData();    LinkList nextNode;    /**     * 在链表末尾添加节点     * @param linkList  被添加的链表对象     * @param data 需要添加的节点对象     * @return 返回添加完成的节点     */    LinkList addLinkListAtEnd(LinkList linkList,LinkListData data){        //node 表示需要添加的末尾对象        // headTemp用于存储临时赋值变量        LinkList node,headTemp;        node = new LinkList(); //申请保存节点数据的内存空间        if (node==null){            System.out.println("内存申请失败,节点为空");            return null;        }else {            node.nodeData = data; //将需要添加的数据对象赋值给申请的节点            node.nextNode = null; //将引用节点设置为空,表示这是末尾节点            if (linkList==null){ //如果当前链表还没有存储对象                linkList = node ;                return linkList;            }else {                headTemp = linkList; //将当前链表赋值给headTemp                while (headTemp.nextNode!=null){ //查找链表尾节点                    headTemp=headTemp.nextNode;                }                headTemp.nextNode = node;                return linkList;            }        }    }    /**     * 在链表头部添加节点     * @param linkList     * @param data     * @return     */    LinkList addLinkListAtHead(LinkList linkList,LinkListData data){        LinkList node = new LinkList();        if (node==null){            System.out.println("内存申请失败,节点为空");            return null;        }else {            node.nodeData = data;            node.nextNode = linkList;            linkList = node;            return linkList;        }    }    /**     * 通过关键词查询链表     * @param linkList     * @param key     * @return     */    LinkList findLinkListByKey(LinkList linkList,String key){        LinkList tmpLinkList = linkList; //保存头节点引用        while (tmpLinkList!=null){            if (tmpLinkList.nodeData.key.compareTo(key)==0){                return tmpLinkList;            }else {                tmpLinkList = tmpLinkList.nextNode;            }        }        return null;    }    /**     * 插入节点,找到关键节点并排其后面     * @param linkList     * @param findKey 插入节点需要找到对应位置,链表查找位置的条件,     * @param data     * @return     */    LinkList insertLinkList(LinkList linkList,String findKey,LinkListData data){        LinkList node,nodeTemp;        node = new LinkList();        if (node==null){            System.out.println("内存申请失败,节点为空");            return null;        }else {            node.nodeData = data;            nodeTemp = findLinkListByKey(linkList,findKey);            if (nodeTemp!=null){                node.nextNode = nodeTemp.nextNode;                nodeTemp.nextNode = node;            }else {                System.out.println("没有找到插入的位置");            }            return linkList;        }    }    /**     * 删除节点     * @param linkList     * @param findKey     * @return 成功返回1 失败返回0     */    int delLinkList(LinkList linkList,String findKey){        LinkList node=linkList,nodeTemp=linkList;        while (nodeTemp!=null){            /**             * 具体操作如下             * 假如链表为  1——> 2 ——> 3 ——> 4 需要删除3             * node 第一轮为 1——> 2 ——> 3 ——> 4             * nodeTemp 第一轮为  2 ——> 3 ——> 4             * node 第二轮为  2 ——> 3 ——> 4             * nodeTemp 第二轮为   3 ——> 4             * 第三轮时 nodeTemp 的 头节点关键词为3 执行if 操作             * 此时  node.nextNode ==> 3 ,nodeTemp.nextNode ==> 4             * 将 node.nextNode = nodeTemp.nextNode;             *那么得到的 node 的链表全结果为  1 ——> 2 ——> 3 ——> 4             *             */            if (nodeTemp.nodeData.key.compareTo(findKey)==0){                node.nextNode = nodeTemp.nextNode;                nodeTemp = null;  //释放内存                return 1;            }else {                node = nodeTemp;                nodeTemp=nodeTemp.nextNode;            }        }        return 0;    }    /**     * 得到链表长度     * @param linkList     * @return     */    int getLengthLinkList(LinkList linkList){        LinkList tmpLinkList = linkList;        int l = 0;        while (tmpLinkList!=null){            l++;            tmpLinkList=tmpLinkList.nextNode;        }        return l;    }    /**     * 显示所有节点内容     * @param linkList     */    void showAllLinkListNodes(LinkList linkList){        int i= 0;        LinkList tmpLinkList = linkList;        LinkListData data;        while (tmpLinkList!=null){            i++;            data = tmpLinkList.nodeData;            System.out.println("第 "+i+" 个节点内容为 "+data.toString());            tmpLinkList = tmpLinkList.nextNode;        }    }    public static void main(String[] args) {        LinkList linkList ;        LinkList headNode = null;        LinkList LINK = new LinkList();        String key;        Scanner sc = new Scanner(System.in);        System.out.println("输入数据,关键词,姓名,年龄");        do {            LinkListData data = new LinkListData();            data.key = sc.next();            if (data.key.equals("0")){                break;            }else {                data.name = sc.next();                data.age = sc.nextInt();                headNode = LINK.addLinkListAtEnd(headNode,data); //向headNode中添加节点            }        }while (true);        //显示        LINK.showAllLinkListNodes(headNode);        System.out.println("删除节点关键词");        key = sc.next();        LINK.delLinkList(headNode,key);        LINK.showAllLinkListNodes(headNode);        System.out.println("查询关键词");        key = sc.next();        linkList = LINK.findLinkListByKey(headNode,key);        if (linkList!=null){            System.out.println(key+" 查询结果为:"+linkList.nodeData.toString());        }else {            System.out.println(key+" 无此结果");        }    }}class LinkListData{    String key;    String name;    int age;    @Override    public String toString() {        return "LinkListData{" +                "key='" + key + '\'' +                ", name='" + name + '\'' +                ", age=" + age +                '}';    }}

3.栈

从数据的运算分类上看为栈,先进后出。从数据的逻辑结构看是一种线性结构。这里主要说的是顺序栈,即在物理内存中连续存在。链式栈是链式结构存储在内存中的。栈的先进后出机制即先入栈的必须在其他节点弹出后才能取出,在栈中,只能访问当前栈顶的元素,当弹出后才能访问下一个。一般有两个操作,入栈和出栈。
入栈即将数据保存到栈顶,出栈即修改栈顶的引用使其指向下一个元素。
这里可以想象为一个特殊的数组形式,里面存放的是节点保存的数据类型可以是一个封装好的实体类等。而这个数组在添加时按照一定顺序,下标为0的保存栈底的节点,以此类推,当有n个节点保存后,栈顶的指向为n-1。在访问时,首先只能访问第n-1个,访问后将指向改为n-2,以此类推访问至最后一个节点。

 package baseDataStructure;import java.util.Scanner;/** * 自定义顺序栈的实现 * 栈是一个先入后出的线性表 * 一般拥有入栈(push) 出栈(pop)两个操作 */public class SequenceStack {    static final int MAXLEN = 50;    SequenceStackData[] data = new SequenceStackData[MAXLEN+1];    int top;    /**     * 栈的初始化     * @return     */    SequenceStack init(){        SequenceStack stack = new SequenceStack();        if (stack!=null){            stack.top = 0;  //申请成功后申请栈顶为0            return stack;        }        return null;    }    /**     * 判断是否为空栈,当栈顶top引用为0时,栈为空     * @param stack     * @return 为空返回true     */    boolean stackIsEmpty(SequenceStack stack){        return stack.top==0;    }    /**     * 判断栈是否已经满了,当栈顶top达到最大值时,栈满     * @param stack     * @return 满了返回true     */    boolean stackIsFull(SequenceStack stack){        if (stack.top==MAXLEN){            return true;        }else {            return false;        }    }    /**     * 设置栈为空,将top引用置为0     * @param stack     */    void stackClear(SequenceStack stack){        stack.top = 0;    }    /**     * 释放栈空间     * @param stack     */    void stackFree(SequenceStack stack){        if (stack!=null){            stack = null;        }    }    /**     * 入栈操作     * @param stack     * @param data     * @return     */    int stackPush(SequenceStack stack,SequenceStackData data){        if (stack.top>=MAXLEN){            System.out.println("栈已满,无法入栈");            return 0;        }else {            stack.data[++stack.top]=data; //元素入栈            return 1;        }     }    /**     * 出栈操作     * @param stack     * @return     */    SequenceStackData stackPop(SequenceStack stack){        if (stack.top==0){            System.out.println("栈内没有元素内容");            return null;        }else {           return  stack.data[stack.top--];        }    }    /**     * 读取节点数据     * @param stack     * @return     */    SequenceStackData getStackData(SequenceStack stack){        if (stack.top==0){            System.out.println("没有数据在栈内");            System.exit(0);        }        return stack.data[stack.top];    }    /**     * 测试实例     * @param args     */    public static void main(String[] args) {        SequenceStack stack = new SequenceStack();        SequenceStackData data = new SequenceStackData();        stack = stack.init(); //初始化        Scanner sc = new Scanner(System.in);        System.out.println("入栈,输入姓名,年龄");        do {            SequenceStackData tmpData = new SequenceStackData();            tmpData.name = sc.next();            if (tmpData.name.equals("0")){                break;            }else {                tmpData.age = sc.nextInt();                stack.stackPush(stack,tmpData);            }        }while (true);        String temp = "1";        System.out.println("出栈:任意非0键进行出栈操作");        temp = sc.next();        while (!temp.equals("0")){            data = stack.stackPop(stack);            System.out.println(data.toString());            temp = sc.next();        }        System.out.println("释放空间");        stack.stackFree(stack);    }}/** * 简单定义栈内节点数据封装类 */class SequenceStackData{    String name;    int age;    @Override    public String toString() {        return "SequenceStackData{" +                "name='" + name + '\'' +                ", age='" + age + '\'' +                '}';    }}

4.队列

队列从数据的逻辑结构上讲也是一种线性结构,这里也主要讲顺序队列结构,还有一种链式队列结构。队列是先进先出的规则。一般有两种操作。入队操作,将节点添加到队尾。出队操作:从队头取出节点并删除,使下一个节点成为队头。

 package baseDataStructure;import java.util.Scanner;/** * 自定义顺序队列结构 * 先进先出 * */public class SequentialQueue {    static final int QUEUELEN = 15;    QueueData[] data = new QueueData[QUEUELEN];    int head;    int tail; //定义队头和队尾    SequentialQueue queueInit(){        SequentialQueue queue; //申请内存        if ((queue=new SequentialQueue())!=null){            queue.head = 0;  //设置队头为0            queue.tail = 0;  //设置队尾为0            return queue;        }else {            return null;        }    }    /**     * 判断队列是否为空     * @param queue     * @return 返回0为空     */    int queueIsEmpty(SequentialQueue queue){        if (queue.head==queue.tail){            return 0;        }else {            return 1;        }    }    /**     * 判断队列是否已满     * @param queue     * @return 返回0为满     */    int queueIsFull(SequentialQueue queue){        if (queue.tail>=QUEUELEN){            return 0;        }else {            return 1;        }    }    /**     * 清空队列     * @param queue     */    void queueSetClear(SequentialQueue queue){        queue.head = 0;        queue.tail = 0;    }    /**     * 释放内存     * @param queue     */    void queueSetFull(SequentialQueue queue){        if (queue!=null){            queue = null;        }    }    /**     * 入队操作     * @param queue     * @param data     * @return 返回1成功 0失败     */    int queueIn(SequentialQueue queue,QueueData data){        if (queue.tail==QUEUELEN){            System.out.println("队列已满");            return(0);        }else {            queue.data[queue.tail++]=data;            return(1);        }    }    /**     * 出队操作     * @param queue     * @return     */    QueueData queueOut(SequentialQueue queue){        if (queue.head==queue.tail){            System.out.println("出对操作:队列已空");            System.exit(0);        }else {            return queue.data[queue.head++];        }        return null;    }    /**     * 读取队列数据操作     * @param queue     * @return     */    QueueData queueGet(SequentialQueue queue){        if (queueIsEmpty(queue)==0){            System.out.println("队列已空");            return null;        }else {            return queue.data[queue.head];        }    }    /**     * 计算队列长度     * @param queue     * @return     */    int queueLen(SequentialQueue queue){        return (queue.tail-queue.head);    }    /**     * 测试实例     * @param args     */    public static void main(String[] args) {        SequentialQueue queue = new SequentialQueue();        QueueData data;        Scanner sc = new Scanner(System.in);        queue = queue.queueInit();        System.out.println("进行入队操作:输入姓名,年龄");        do {            QueueData queueData = new QueueData();            queueData.name = sc.next();            queueData.age = sc.nextInt();            if (queueData.name.equals("0")){                break;            }else {                queue.queueIn(queue,queueData);            }        }while (true);        String temp = "1";        System.out.println("出队列操作,输入任何非0键位");        temp = sc.next();        while (!temp.equals("0")){            data = queue.queueOut(queue);            System.out.println("队列内容为 "+data.toString());            temp = sc.next();        }        System.out.println("释放内存");        queue.queueSetFull(queue);    }}/** * 简单队列节点对象数据封装 */class QueueData{    String name;    int age;    @Override    public String toString() {        return "QueueData{" +                "name='" + name + '\'' +                ", age=" + age +                '}';    }}