zoukankan      html  css  js  c++  java
  • 数据结构回顾之顺序存储结构中的线性表(栈与队列顺序线性表实现)

     

      说到数据结构呢,对于一个Coder来说还是蛮重要的啦,每次看数据结构的东西都有新的收获,这两天在回顾数据结构的知识。当然啦,虽然数据结构有些是理论的东西,如果好好的理解数据结构的东西还是少不了的代码的支撑的。数据结构简单的来说吧,可以分为两大类,一个是数据的“物理存储结构”,另一种是数据的“逻辑存储结构”。数据的“物理存储结构”又可分为顺序的和链式的(下面将会结合着代码打印内存地址的形式来观察物理存储结构)。 逻辑存储结构又可分为集合,线性, 树,图这些东西。

      数据结构说白了就是如何利用上面的那些东西来储存我们的数据,目的是方便我们对数据的管理和使用,至于选择何种数据结构来存储我们的数据,这要根据具体情况具体分析。

      好啦,废话少说,切入今天的正题。本篇博客的主题是介绍顺序存储结构下的线性表,然后又给出啦顺序物理存储结构下的栈和队列,当然是对线性表的应用了。基础代码的编写是用C语言写的,最后给出了OC中的栈和队列的实现方式。好啦,这次真的不说废话了,代码走起。

       1.定义顺序线性表的宏定义和类型重定义如下,MAXSIZE为线性表的最大容量, SUCCESS为成功后的返回代码,ERROR为失败后的返回代码

    复制代码
     1 //  main.m
     2 //  DataStructList
     3 //
     4 //  Created by 李泽鲁 on 14-11-4.
     5 //  Copyright (c) 2014年 Mrli. All rights reserved.
     6 //
     7 
     8 #import <Foundation/Foundation.h>
     9 #define MAXSIZE 10             //线性表顺序存储结构的最大容量
    10 /*
    11  *定义状态代码
    12  */
    13 #define SUCCESS 1
    14 #define ERROR 0
    15 
    16 typedef int Status;            //状态代码的类型
    17 typedef int ElemType;          //顺序线性表中存储的元素类型
    复制代码

      3.定义顺序线性表的存储结构,当然啦,既然物理上是顺序的(内存地址连续的),所以我们就用一维数组来储存线性表中的元素。length为数据元素的个数

    1 //顺序存储结构定义
    2 typedef struct {
    3     ElemType data[MAXSIZE];     //用数组来表示顺序线性表
    4     int length;
    5 } SqList;

      4.线性表的初始化,为我的的线性表分配存储内存(用malloc分配内存),并初始化length为0。返回值为分配内存的首地址,也就是线性表的指针,代码如下:

    复制代码
    1 /*
    2  *线性表的初始化,分配内存,并初始化元素的个数
    3  */
    4 SqList* initSqlist()
    5 {
    6     SqList *myList = (SqList *) malloc(sizeof(SqList));
    7     myList->length = 0;
    8     return myList;
    9 }
    复制代码

      5.接下来我们就要写如何往线性表中增加元素了

        (1),以栈的形式来往我们的顺序线性表中增加元素,也就是每次往线性表中的末尾添加元素。在前面的iOS部分的博客中的UINavigationController中提到了栈的概念,下面的代码就是入栈的过程。用大白话说,就是往线性表的末尾添加元素。在添加之前呢,要判断该线性表是否有额外的空间来容纳我们要入栈的元素。代码如下:

    复制代码
     1 /*
     2  *增加元素(以栈的形式添加元素,往线性表的尾部添加元素)--(入栈)
     3  */
     4 Status pushElement(ElemType element, SqList *list)
     5 {
     6     int length = list->length;
     7     //判断线性表的合法性
     8     if (length < 0 || length >= MAXSIZE)
     9     {
    10         return ERROR;
    11     }
    12     
    13     //length合法,往尾部添加元素
    14     list->data[length] = element;
    15     list->length ++;
    16     
    17     return SUCCESS;
    18 }
    复制代码

        (2)、上面的是入栈,也就是从尾部添加元素,接下啦就是如何往任意的合法位置插入元素。顺序线性表插入元素的思想是从后往前为我们的要插入的位置腾空,腾出空来,我们就插入元素,然后length加一,代码如下:

    复制代码
     1 //顺序线性表插入元素
     2 Status insertElementWithLocation(ElemType elment, SqList *list, int location)
     3 {
     4     int length = list->length;
     5     //判断线性表的合法性
     6     if (length < 0 || length >= MAXSIZE)
     7     {
     8         return ERROR;
     9     }
    10     
    11     //判断位置的合法性
    12     if (location < 0 || location > length)
    13     {
    14         return ERROR;
    15     }
    16     
    17     //插入元素
    18     for(int i = length; i >= 0; i --)
    19     {
    20         //元素从后往前移动,给插入的位置腾出空
    21         if (i >= location)
    22         {
    23             list->data[i] = list->data[i-1];
    24         }
    25         else
    26         {
    27             //腾出位置以后结束循环
    28             break;
    29         }
    30     }
    31     
    32     //往插入的位置赋新的值
    33     list->data[location] = elment;
    34     list->length ++;
    35     
    36     return SUCCESS;
    37 }
    复制代码

        (3)、接下来就是队列出场的时候啦,队列增加元素是从头插入的,所以我们只需调用上面的插入函数就可以实现入队列的功能,代码如下:

    复制代码
     1 //按队列的形式增加元素(入队列)
     2 Status intoQueueWithElement(ElemType element, SqList *list)
     3 {
     4     //调用插入语句,往顺序线性表中的头部添加元素,也就是如对列的围脖
     5     Status error = insertElementWithLocation(element, list, 0);
     6     
     7     if (error == ERROR) {
     8         return ERROR;
     9     }
    10     return SUCCESS;
    11 }
    复制代码

      6、上面的部分是增加元素,下面就开始我们的删除元素的部分

        (1)、还是按照上面的思路来,看一下顺序存储结构下的线性表的栈是如何删除元素的。当然啦,这个很简单啦,也就是出栈的过程,从线性表的末尾移除元素即可,同时length减一,代码如下:

    复制代码
     1 /**
     2  *以栈的形式来删除元素--(出栈),*element用于接收pop出的值
     3  */
     4 Status popElement(ElemType *element,SqList *list)
     5 {
     6     int length = list->length;
     7     //判断线性表的合法性
     8     if (length < 0 || length >= MAXSIZE)
     9     {
    10         return ERROR;
    11     }
    12     
    13     
    14     *element = list->data[length - 1];
    15     list->length --;
    16     
    17     return SUCCESS;
    18     
    19 }
    复制代码

      

        (2)、给出位置删除元素的代码如下,这个正好和给出位置增加元素相反,这个是从删除的位置依次覆盖,然后length减一即可,代码如下

    复制代码
     1 //删除指定位置的元素
     2 Status deleteElementWithLocation(ElemType *element, SqList *list, int location)
     3 {
     4     int length = list->length;
     5     //判断线性表的合法性
     6     if (length < 0 || length >= MAXSIZE)
     7     {
     8         return ERROR;
     9     }
    10     
    11     //判断位置的合法性
    12     if (location < 0 || location >= length)
    13     {
    14         return ERROR;
    15     }
    16     
    17     //取出要删除的元素
    18     *element = list->data[location];
    19     
    20     //覆盖掉要删除的元素
    21     for (int i = location; i < length-1; i ++) {
    22         list->data[i] = list->data[i+1];
    23     }
    24     list->length --;
    25 
    26     
    27     return SUCCESS;
    28 }
    复制代码

        (3)出队列的过程和出栈的过程是一样的,都是从线性表的最后删除元素,代码如下:

    复制代码
     1 //出队列,和出栈一样,都是取出最后一个元素
     2 Status outQueueWithList(ElemType *element, SqList *list)
     3 {
     4     
     5     Status error = popElement(element, list);
     6     if (error == ERROR) {
     7         return ERROR;
     8     }
     9     return SUCCESS;
    10 }
    复制代码

      7、遍历我们的顺序线性表,代码如下:

    复制代码
     1 /*
     2  *遍历顺序线性表
     3  */
     4  Status displayList(SqList *list)
     5 {
     6     int length = list->length;
     7     //判断线性表的合法性
     8     if (length < 0 || length >= MAXSIZE)
     9     {
    10         return ERROR;
    11     }
    12 
    13     NSLog(@"********************************");
    14     for (int i = 0; i < list->length ; i ++) {
    15         NSLog(@"数值 = %d,内存地址 = %p", list->data[i], &list->data[i]);
    16     }
    17     NSLog(@"********************************
    
    ");
    18     
    19     return SUCCESS;
    20 }
    复制代码

      8、基本代码编写完毕,下面就该我们做测试啦

        (1),首先在main函数中进行线性表的初始化,然后push进5个数字,并输出。由输出结果可以看出,在内存中的地址是连续的,并且是从线性表的末尾添加的元素代码如下:

    复制代码
     1     //初始化顺序线性表
     2     SqList *list = initSqlist();
     3     
     4     NSLog(@"把1-5按顺序入栈");
     5     //往顺序线性表中以栈的存储方式存入值,入栈
     6     for (int i = 1; i < 6; i ++) {
     7         pushElement(i, list);
     8     }
     9     //遍历线性表
    10     displayList(list);
    复制代码

        运行结果如下:

        

        (2)、测试往任意的位置插入值(为了整齐,后来运行的时候把10,给改成了8),代码如下,内存地址当然也是连续的啦

    1     //往第0个位置插入数值10;
    2     NSLog(@"往第0个位置插入数值10");
    3     insertElementWithLocation(8, list, 0);
    4     displayList(list);

           运行结果如下:

        

        (3)、出栈的测试代码如下

    1     //出栈
    2     ElemType element;  //用于接收pop出的值
    3     popElement(&element, list);
    4     NSLog(@"出栈后的值为:%d, 值的地址为:%p", element, &element);
    5     displayList(list);

          运行结果如下:

        (4)、入队列的测试代码如下:

        //入队列
        NSLog(@"把9入队列");
        intoQueueWithElement(9, list);
        displayList(list);

          运行结果如下:

        (5)、出队列的测试代码如下:(下面NSlog打印的时候有的小错误,把出栈应该换成出队列,因为是截得图,所以就不改了,在这声明一下的啦)。

    1     //出队列
    2     ElemType lastElement;
    3     outQueueWithList(&lastElement, list);
    4     NSLog(@"出栈后的值为:%d, 值的地址为:%p", lastElement, &lastElement);
    5     displayList(list);

          运行结果如下:

        (6)、删除指定位置的元素,测试代码如下:

    复制代码
    1     //删除指定位置上的数据
    2     NSLog(@"删除下标为三的元素");
    3     ElemType deleteElement;
    4     deleteElementWithLocation(&deleteElement, list, 3);
    5     NSLog(@"被删除的值为:%d, 内存地址:%p", deleteElement, &deleteElement);
    6     displayList(list);
    复制代码

          运行结果如下:

      上面呢就是用C语言描述的顺序存储结构下的线性表了,其中也给出了队列和栈的操作。那么在OC中如何使用栈和队列的结构呢?其实蛮简单的,用NSMutableArray就完全可以实现上述的操作,因为苹果已经给我们封装好啦,直接用就可以了。不过原理性的东西还是要明白的。有关NSMutableArray的东西,请参考前面有关OC部分的博客:Objective-C中的集合类 ,栈和队列的使用请参考iOS部分的iOS开发之画图板(贝塞尔曲线),今天的博客就先到这,欢迎批评指正。

    作者:青玉伏案 
    出处:http://www.cnblogs.com/ludashi/ 
    本文版权归作者和共博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。 
    如果文中有什么错误,欢迎指出。以免更多的人被误导。

  • 相关阅读:
    mysql 历史版本下载
    mysql 5.7 版本 You must reset your password using ALTER USER statement before executing this statement报错处理
    5.7 zip 版本的安装 以及遇到的坑
    mysql 5.6zip版本的卸载与5.7 zip 版本的安装
    mysql数据库的备份与还原
    本地Navicat连接docker里的mysql
    docker修改数据库密码
    docker 在push镜像到本地registry出现的500 Internal Server Error
    linux 没有界面内容显示不全解决办法
    json与map互相转换
  • 原文地址:https://www.cnblogs.com/xujiahui/p/6393252.html
Copyright © 2011-2022 走看看