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


知识框架

在这里插入图片描述

基本操作代码

#include <iostream>
using namespace std;

/**
 * 1.顺序表的定义
 * 两种方式:静态分配和动态分配
 */

//1.1静态分配
#define MAXSIZE 50   //定义线性表的最大长度
typedef struct {
    int data[MAXSIZE];//ElemType data[MaxSize] 顺序表的元素
    int length; //顺序表的当前长度
}SqList;//顺序表的类型定义

//1.2动态分配
#define InitSize 5 //表长度的初始定义
typedef struct {
    int *data; //指示动态分配数组的指针
    int MaxSize; //数组的最大容量
    int length; //数组的当前长度
}SeqList;

/**
 * 2.顺序表的基本操作:以动态
 * 创建(初始化) 销毁 插入 删除 按值查找 打印输出
 */

//2.1创建
void InitList(SeqList &L){
    //用malloc函数申请一片连续的存储空间
    L.data = (int *) malloc(InitSize * sizeof (int));
    L.length = 0;
    L.MaxSize = InitSize;
}

//2.2销毁
void DestroyList(SeqList &L){
    free(L.data);
}

//2.3增加动态数组的长度
void IncreaseSize(SeqList &L,int len){
    //指针p指向data的内存区域
    int *p = L.data;
    //data重新开辟一片更大的存储空间
    L.data = (int *) malloc( (L.MaxSize+len) * sizeof (int));
    //把原来的数据放到新开辟的内存空间来
    for (int i = 0; i < L.length; ++i) {
        L.data[i] = p[i];
    }
    //扩容后改变原来的最大的容量
    L.MaxSize = L.MaxSize + len;
    //释放掉原来开辟的区域
    free(p);
}

//2.4插入
bool ListInsert(SeqList &L,int i,int e){
    //判断i的范围是否有效
    if (i < 1||i > L.length+1){
        return false;
    }
    //第i个以后的元素(包含第i个)都往后移一位【从最后一个元素开始移】
    for (int j = L.length; j >= i; --j) {
        L.data[j] = L.data[j-1];
    }
    //把e放入第i个
    L.data[i-1] = e;
    //长度+1
    L.length++;
    return true;
}

//2.5删除:删除顺序表中第i个元素,用引用变量e返回
bool ListDeleted(SeqList &L,int i,int &e){
    //判断位置i的合法性
    if (i > L.length||i <= 0){
        return false;
    }
    //删除逻辑操作
    e = L.data[i-1];
    for (int j = i; j < L.length; ++j) {
        L.data[j-1] = L.data[j];
    }
    L.length--;
    return true;
}

//2.6按值查找
int LocatedElem(SeqList L,int e){
    for (int i = 0; i < L.length; ++i) {
        if (L.data[i] == e){
            return i+1;
        }
    }
    return -1;
}

//2.7打印输出
void PrintData(SeqList L){
    for (int i = 0; i < L.length; ++i) {
        cout<<L.data[i]<<"  ";
    }
    cout<<"元素个数:"<<L.length<<"  容量:"<<L.MaxSize;
    cout<<endl;
}


int main() {
    //创建顺序表L
    SeqList L;
    InitList(L);
    //赋值
    for (int i = 0; i < L.MaxSize; ++i) {
        L.data[i] = i;
        L.length++;
    }
    //打印
    PrintData(L);
    //扩容
    IncreaseSize(L,5);
    PrintData(L);
    //插入
    ListInsert(L,3,9);
    PrintData(L);
    //按值查找
    int l = LocatedElem(L,4);
    cout<<"位置:"<<l<<endl;
    //删除
    int e = -1;
    ListDeleted(L,4,e);
    PrintData(L);
    //销毁
    DestroyList(L);

    return 0;
}

注意点

  1. 存取方式是指读写方式。顺序表是一种支持随机存取的存储结构,根据起始地址加上元素的序号,可以很方便地访问任意一个元素。
  2. 顺序表:逻辑上相邻的数据元素物理上也相邻。

应用题

  1. 从顺序表中删除具有最小值的元素(假设唯一)并由函数返回被删除元素的值。空出的位置由最后一个元素填补,若顺序表为空则显示出错信息并退出运行。
#include <iostream>
using namespace std;

typedef struct {
    int *data;
    int length;
    int MaxSize;
}SeqList;

/**
 * 1.从顺序表中删除具有最小值的元素(假设唯一)并由函数返回被删除元素的值。
 * 空出的位置由最后一个元素填补,若顺序表为空则显示出错信息并退出运行。
 */
bool Del_Min(SeqList &L,int &e){
    if (L.length == 0){
        return false;
    }

    //找到最小值的下标
    int min_index = 0;
    for (int i = 0; i < L.length; ++i){
        if (L.data[i] < L.data[min_index]){
            min_index = i;
        }
    }
    //e返回删除的值
    e = L.data[min_index];
    //最后一个元素填补删除的值
    L.data[min_index] = L.data[L.length-1];
    return true;
}

int main() {
    SeqList L;
    L.data = (int *) malloc(5*sizeof (int));
    L.MaxSize = 5;
    
    L.data[0] = 8;
    L.data[1] = 2;
    L.data[2] = 4;
    L.data[3] = 5;
    L.data[4] = 3;
    
    L.length = 5;
    int e = -1;
    if (Del_Min(L,e)){
        for (int i = 0; i < L.length; ++i){
            cout<<L.data[i]<<"  ";
        }
    }
    cout<<endl;
    cout<<e<<endl;
    return 0;
}

  1. 设计一个高效算法,将顺序表L的所有元素逆置,要求算法的空间复杂度为O(1)
#include <iostream>
using namespace std;

typedef struct {
    int *data;
    int length;
    int MaxSize;
}SeqList;

/**
 *2. 设计一个高效算法,将顺序表L的所有元素逆置,要求算法的空间复杂度为O(1)
 */
void Reverse(SeqList &L){
    //扫描顺序表L的前半部分元素L.data[i] (0<=i<L.length/2)
    // 将其与后半部分的对应元素L.data[L.length-1-i]进行交换。
    int temp;
    for (int i = 0; i < L.length/2; ++i){
        temp = L.data[i];
        L.data[i] = L.data[L.length-i-1];
        L.data[L.length-i-1] = temp;
    }
}

int main() {
    SeqList L;
    L.data = (int *) malloc(5*sizeof (int));
    L.MaxSize = 5;

    L.data[0] = 1;
    L.data[1] = 2;
    L.data[2] = 3;
    L.data[3] = 4;
    L.data[4] = 5;

    L.length = 5;
    Reverse(L);
    for (int i = 0; i < L.length; ++i){
        cout<<L.data[i]<<"  ";
    }
    cout<<endl;
    return 0;
}

  1. 顺序表–对长度为n的顺序表L,编写一个时间复杂度为O(n),空间复杂度为O(1)的算法,该算法删除线性表中所有值为x的数据元素。
/**
 * 3.顺序表--对长度为n的顺序表L,编写一个时间复杂度为O(n),空间复杂度为O(1)的算法,
 * 该算法删除线性表中所有值为x的数据元素
 */

//用k记录线性表L中 不等于 x的个数,边扫描,便统计k,不等于 x的元素移动到第k个位置上

void del_x_1(SeqList &L,int x){
    int k = 0;
    for (int i = 0; i < L.length; ++i){
        if (L.data[i] != x){
            L.data[k] = L.data[i];
            k++;
        }
    }
    L.length = k; 
}
  1. 有序顺序表中删除其值在给定值s与t之间(要求s<t)的所有元素,如果s或t 不合理或者顺序表为空则显示出错信息并退出运行。
/**
 * 4. 从有序顺序表中删除其值在给定值s与t之间(要求s<t)的所有元素,
 *    如果s或t 不合理或者顺序表为空则显示出错信息并退出运行。
 */

//注意是有序表,找到s到t这一段的元素删除即可
 bool del_s_t(SeqList &L,int s,int t){
    if (s >= t || L.length == 0){
        return false;
    }
    int m=0,n=0;
    for (int i = 0; i < L.length; ++i){
        if (L.data[i] > s){
            m = i;
            break;
        }
    }
    if ( m == 0){
        return false; //所有元素都小于s
    }
    for (int i = m; i < L.length; ++i){
        if (L.data[i] > t){
            n = i;
            break;
        }
    }
    //删除下标m~(n-1)
    for (int i = n; i < L.length; ++i){
        L.data[m] = L.data[i];
        m++;
    }
    L.length = m;
    return true;
    
 }
  1. 从顺序表中删除其值在给定值s与t之间(包含s和t,要求s<t)的所有元素,如果 s或t不合理或者顺序表为空则显示出错信息并退出运行。
 /**
  * 5. 从顺序表中删除其值在给定值s与t之间(包含s和t,要求s<t)的所有元素,
  *    如果 s或t不合理或者顺序表为空则显示出错信息并退出运行。
  */
 bool del_s_t2(SeqList &L,int s,int t){
     if (s>=t || L.length == 0){
         return false;
     }
     int k = 0;//统计合格元素的个数
     for (int i = 0; i < L.length; ++i){
         if (L.data[i] < s || L.data[i] > t){
             L.data[k] = L.data[i];
             k++;
         }
     }
     L.length = k;
     return true;
 }
  1. 有序顺序表中删除所有其值重复的元素,使表中所有元素的值均不同。
 /**
  * 6. 从有序顺序表中删除所有其值重复的元素,使表中所有元素的值均不同。
  */
  //有序
  bool no_repeat(SeqList &L){
      if(L.length == 0){
          return false;
      }
      int k = 1;//记录合格元素个数,默认下标为0是不重复元素
      int p = L.data[0];//记录上一个元素的值
      for (int i = 1; i < L.length; ++i){
          //当前元素不等于它前一个元素(合格)
          if (L.data[i] != p){
              L.data[k] = L.data[i];
              k++;
              p = L.data[i];
          }
      }
      L.length = k;
      return true;
  }

(补充:从顺序表中删除所有其值重复的元素,使表中所有元素的值均不同。无序)

  1. 将两个有序的顺序表合并成一个新的有序顺序表,并由函数返回结果顺序表。
  SeqList merge(SeqList &L1,SeqList &L2){
      SeqList L;
      L.data = (int *) malloc(sizeof (int )*(L1.length+L2.length));
      int i = 0; //记录L1的位置
      int j = 0; //记录L2的位置
      int k = 0; //记录L的位置
      while (i < L1.length && j <L2.length){
          if (L1.data[i] < L2.data[j]){
              L.data[k] = L1.data[i];
              i++;
              k++;
          } else {
              L.data[k] = L2.data[j];
              j++;
              k++;
          }
      }

      while (i < L1.length){
          L.data[k] = L1.data[i];
          i++;
          k++;
      }
      while (j <L2.length){
          L.data[k] = L2.data[j];
          j++;
          k++;
      }
      L.length = k;
      return L;
  }


int main() {
    SeqList L1;
    L1.data = (int *) malloc(5*sizeof (int));
    L1.MaxSize = 5;

    L1.data[0] = 1;
    L1.data[1] = 2;
    L1.data[2] = 4;
    L1.data[3] = 6;
    L1.data[4] = 7;

    L1.length = 5;

    SeqList L2;
    L2.data = (int *) malloc(5*sizeof (int));
    L2.MaxSize = 5;

    L2.data[0] = 3;
    L2.data[1] = 8;
    L2.data[2] = 9;
    L2.data[3] = 11;
    L2.data[4] = 14;

    L2.length = 5;


    SeqList  L = merge(L1,L2);
    for (int i = 0; i < L.length; ++i){
        cout<<L.data[i]<<"  ";
    }
    cout<<endl;
    return 0;
}
  1. 已知在一维数组A[m+n]中依次存放两个线性表(a1, a2, 3,. am)和(b1, b2, b…,bn).将数组中两个顺序表的位置互换,即将(b1,b2,b3,…,bn)放在(a1,a2,a3,…,am)的前面。
  /**
   * 8. 已知在一维数组A[m+n]中依次存放两个线性表(a1, a2, 3,. am)和(b1, b2, b...,bn).
   * 将数组中两个顺序表的位置互换,即将(b1,b2,b3,...,bn)放在(a1,a2,a3,...,am)的前面。
   */

  void reverse(int A[],int left,int right,int arraySize){
      if (left>=right || right >= arraySize){
          return;
      }
      while (right > left){
          int temp = A[left];
          A[left] = A[right];
          A[right] = temp;
          right--;
          left++;
      }
  }

  bool exchange(int A[],int n,int m,int arraySize){
      //先将A逆置:bn,...,b1,am,...,a1
      //在将前n个逆置:b1,..,b2,am,...,a1
      //最后将第n+1~m+n个逆置:b1,..,bn,a1,...,am
      reverse(A,0,m+n-1,arraySize);
      reverse(A,0,n-1,arraySize);
      reverse(A,n,n+m-1,arraySize);
  }

int main() {
    int A[] = {1,3,5,7,2,4,6,8};
    exchange(A,4,4,8);
    for (int i = 0; i < 8; ++i) {
        cout<<A[i]<<"   ";
    }
    return 0;
}
  1. 线性表(a1,a2,a3,…,an)中元素递增有序且按顺序存储于计算机内。要求设计一个算法,完成用最少时间在表中查找数值为x的元素,若找到,则将其与后继元素位置相交换,若找不到,则将其插入表中并使表中元素仍递增有序。
  /**
   * 9. 线性表(a1,a2,a3,…,an)中元素递增有序且按顺序存储于计算机内。
   * 要求设计一个算法,完成用最少时间在表中查找数值为x的元素,
   * 若找到,则将其与后继元素位置相交换,若找不到,则将其插入表中并使表中元素仍递增有序。
   */
   void search_x(SeqList &L,int x){
       //递增有序:采用二分法查找x
       int left = 0;
       int right = L.length-1;
       int mid;
      while (right >= left){
          mid = (right+left)/2;
          if (x > L.data[mid]){
              left = mid+1;
          } else if (x < L.data[mid]){
              right = mid-1;
          } else {
              //找到了
              break;
          }
      }

      //查找成功
      if (L.data[mid] == x && mid != L.length-1){
          L.data[mid] = L.data[mid+1];
          L.data[mid+1] = x;
      } 
      //查找失败
      if (left > right){
          int i;
          for ( i = L.length-1; i > right; --i){
              L.data[i] = L.data[i+1];
          }
          L.data[i+1] = x;
          L.length++;
      }
   }
  1. 设将n (n>1)个整数存放到一维数组R中,设计一个算法,将R中的序列循环左移P (0<P<n) 个位置,即将R中的数据由{Xo,X1, …, Xn-1}变换为{Xp,Xp+1, … Xn-1, X0,X1, …,Xp-1}。要求:
    (1)给出算法的基本设计思想。
    (2) 根据设计思想,采用C或C++语言描述算法,关键之处给出注释。
    (3)说明你所设计的算法的时间复杂度和空间复杂度。

【博主分析:这题完全可以参考第8题解题思路,即对这个数组进行几轮逆置,本题3轮逆置,第一轮:对整个数组逆置变成{Xn-1, …,Xp,Xp-1,…,X1, X0},第二轮:[0,p-1]逆置,变成{Xp, …,Xn-1,Xp-1,…,X1, X0},第三轮:[n-p,n-1],变成{Xp,Xp+1, … Xn-1, X0,X1, …,Xp-1}】

完整答案:
(1)算法的基本设计思想:可将这个问题视为把数组ab转换成数组ba(a代表数组的前p个元素,b代表数组中余下的n -p个元素),先将a逆置得到 a − 1 b a^{-1}b a1b,再将b逆置得到 a − 1 b − 1 a^{-1}b^{-1} a1b1,最后将整个 a − 1 b − 1 a^{-1}b^{-1} a1b1逆置得到 ( a − 1 b − 1 ) − 1 {(a^{-1}b^{-1})}^{-1} a1b11= ba。设Reverse函数执行将数组元素逆置的操作。
(2)

   void reverse(int A[],int left,int right){
       if (left>=right){
           return;
       }
       while (right > left){
           int temp = A[left];
           A[left] = A[right];
           A[right] = temp;
           left++;
           right--;
       }
   }
   
   void Converse(int R[],int n,int p){
       reverse(R,0,p-1);
       reverse(R,p,n-1);
       reverse(R,0,n-1);
   }

(3)时间复杂度O(n),空间复杂度O(1).

  1. 一个长度为L(L≥1)的升序序列S,处在第[L/2]个位置的数称为s的中位数。例如,若序列S1:(11,13,15,17,19),则S1的中位数是15。两个序列的中位数是含它们所有元素的升序序列的中位数。例如,若S2=(2,4,6,8,20),则S1和S2的中位数是11。现有两个等长升序序列A和B,试设计一个在时间和空间两方面都尽可能高效的算法,找出两个序列A和B的中位数。要求:
    1)给出算法的基本设计思想。
    2)根据设计思想,采用C/C++语言描述算法,关键之处给出注释。
    3)说明你所设计算法的时间复杂度和空间复杂度。
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值