[数据结构]第二章-表

来源:互联网 发布:微信商城源码使用 编辑:程序博客网 时间:2024/06/09 15:08

是由n个同一类型的元素a1,a2,…,an组成的有限序列。(元素不可对调,顺序表示了逻辑关系)

·支持的运算:

1.ListEmpty(L):表L是否为空
2.ListLength(L):表L的长度
3.ListLocate(x,L):元素x在表L中的位置(若x在表中重复出现多次,则返回最前面的x的位置)
4.ListRetrieve(k,L):返回表L的位置k处的元素(若表中没有位置k时,该运算无定义)
5.ListInsert(k,x,L):在表L的位置k处插入元素x,并将原位置及之后的元素往后挪
6.ListDelete(k,L):从表L中删除位置k处的元素,并返回被删除的元素(若表中没有位置k时,该运算无定义)
7.PrintList(L):将表L中所有元素按位置的先后次序打印输出

·ADT表的实现:

1.数组实现(顺序存储实现)
–等概论下插入和删除运算的平均性能为n/2、(n-1)/2 时间复杂度O(n)->用于移动元素
–优点:查找方便、随机存取
–缺点:大小固定,不方便动态添加

2.指针实现(非顺序存储实现、链式存储实现)
–增删O(n)->用于遍历链表(与数组实现时的O(n)不同)
–优点:动态添加删除、大小可变
–缺点:查询效率低、需要额外空间来存这一关系

·head结点的作用:简化插入和删除操作(不用特判情况)

·单链表逆置操作
新建:(0 0想法大概是用p1,p2两个指针从左到右扫描,记录每个结点的上一结点pre,再新建一个链表把pre赋值给next(?)
就地:(头插法)一边遍历一边把每个结点插到头结点之后http://blog.chinaunix.net/uid-27033491-id-3349370.html

·单链表合并:
(a1,a2,a2,…an)(b1,b2,b3,…bm)->(O(n+m))
举例:多项式加法
·将单链表b接到a后O(n)(a接到b后O(m))

·循环链表
·双链表

//–作业题

2.3 击鼓传花

这里写图片描述

(要删去的人数为n-1,所以每次只要找到要删去的位置pos,把其后的数都往前移,pos再移到下一位置,这样重复n-1次,最后pos位置的数既是答案。复杂度O(n^2)/O(mn))

#include<iostream>    #include<cstdio>    #include<cmath>    #include<cstring>     using namespace std;    int a[550];    int i;  int main()    {        int n,m;        cin >> n >> m;        for(i = 1; i <= n; i++)          a[i] = i;      int cnt = 0;        int pos = 1;        int len = n;      while(cnt < n-1)         {            //move           for(i = pos+1; i <= len; i++)              a[i-1] = a[i];          len--;          pos += m-1;          while(pos > len) pos-=len;  //        pos = (pos-1)%len + 1;     另一种常用写法        cnt++;        }        cout << a[pos] << endl;        return 0;    }

//思路2 瞎模拟 (这样当删到最后几个未被踢出的结点相当稀疏的时候寻找下一人所花时间较多)

vis[1] = 1, find = 1, cnt =  0, i = 1;while (find != n){    i++;    if (i > n)   i = 1;    if (!vis[i])   cnt++;    if (cnt == m)    vis[i] = 1, cnt = 0, find++;}

//思路3 维护两个数组保存每一结点的前后结点,每当踢出一个结点时将pre[i]的nex值修改为nex[i],nex[i]的pre值修改为pre[i]

    1 2 3 4 5nex 2 3 4 5 1pre 5 1 2 3 4

这里写图片描述

//思路4

约瑟夫环的变形
约瑟夫问题:
一圈共有N个人,从第一个开始报数,报到M的人自杀,然后重新开始报数,问最后自杀的人是谁
如N=6,M=5,被杀掉的顺序是:5,4,6,2,3,1。

把问题稍微改变一下:

N个人(0, 1, 2, … , N-1),从0开始报数,报到M-1的退出,剩下的人继续从0开始报数。求最后退出的人的编号

Round 1:
0 1 2 3 … N-2 N-1
第一个退出的人是(M-1)%N
0 … M-2 (gg) M … N-2 N-1
N-1人组成新环, (由M开始), 即:
M M+1 … N-1 0 1 … M-2

重新编号:
M M+1 … N-1 0 1 … M-2
0 1 … … … … N-2
问题转变为(N-1)个人,报到(M-1)的人自杀 —-> N-1的子问题
假设N-1个人时最后剩下的为x,则N个人时,最后剩下的也是这个人,对应编号为
x’=(x+M)%N

故有递推公式:
令F[i]表示i个人玩游戏报M退出最后胜利者的编号
则有 F[1] = 0
F[i] = (F[i-1] + M) % i (i>1)

回到本题,当n>1时,只要重新编号:
1 2 3 4 … N–1 N
0 1 2 … N-3 N-2
则为(N-1)个人报M退出的约瑟夫问题
故有 F[1] = 0
F[i] = (F[i-1] + M) % i (i>1)
最后答案+2即可

#include <iostream>  using namespace std;  int main()  {      int n, m, i, ans;      cin >> n >> m;      for (ans = 0, i = 2; i <= n - 1; ++i)          ans = (ans + m) % i;      cout << (n == 1 ? 1 : ans + 2) << endl;      return 0;  }

约瑟夫环博客参考:http://blog.csdn.net/kangroger/article/details/39254619

2.4 排队

这里写图片描述

(同理,模拟服务的人以及每隔id个人离开队伍,其后数据往前挪)

#include<cstdio>  #include<iostream>  using namespace std;  #define MAX 10000  int a[MAX + 10];  int i;  int n;  int cnt; //服务人数   int id; //编号   int pos;    int len = MAX;  void move(int p,int N)  {      for(i = p+1; i <= N; i++)          a[i-1] = a[i];      len--;  }  int main()  {      scanf("%d",&n);      for(i = 1; i <= MAX; i++)          a[i] = i+1;           cnt = 0;      id = 2;      pos = 1;      while(cnt < n-1)      {          while(pos < len)          {              move(pos,len);              pos += id-1;          }          cnt++;          id = a[1];          pos = 1;      }      printf("%d\n",a[1]);  }

————
练习题

2.1 塔防

这里写图片描述
这里写图片描述

(线性表的基本操作 增删改查什么的_(:зゝ∠))

#include<iostream>  #include<cstdio>  #include<cmath>  using namespace std;  int a[550];  int i;  int len;  void add(int num)  {      a[len] = num;      len++;  }  void del(int id)  {      for(i = id+1; i < len; i++)          a[i-1] = a[i];      len--;  }  void cge(int id,int num)  {      a[id] = num;  }  int qry(int id)  {      return a[id];  }  int main()  {      int n,m;      scanf("%d%d",&n,&m);      for(i = 0; i < n; i++)          scanf("%d",&a[i]);      len = n;      char s[5];      int index;      int num;      while(m--)      {          scanf("%s",&s);          if(s[0] == 'a')          {              scanf("%d",&num);              add(num);          }          else if(s[0] == 'd')          {              scanf("%d",&index);              del(index);           }          else if(s[0] == 'c')          {              scanf("%d%d",&index,&num);              cge(index,num);          }          else if(s[0] == 'q')          {              scanf("%d",&index);              printf("%d\n",qry(index));          }      }      return 0;  }

2.2 逆序数

这里写图片描述

(对于原数列1,2,3…,n,逆序数i其实就对应了这些数里面第i+1大的数。如果用数组从0开始存储,a[i]就是原数字,如a[4] = 5。找到这个数字之后把它删去,因为这是个单增数组,全部往前挪即可,然后再继续从剩下的数字中找下标为i的数输出。)

#include<iostream>  #include<cstdio>  #include<cmath>  #include<algorithm>  using namespace std;  int a[550];  int num;  int len;  void del(int id)  {      for(int i = id+1;i < len; i++)          a[i-1] = a[i];      len--;  }  int main()  {      int n;      cin >> n;      len = n;      for(int i = 0; i < n; i++)         a[i] = i+1;      cin >> num;      cout << a[num];      del(num);      for(int i = 1; i < n; i++)      {          cin >> num;          cout <<" " << a[num];          del(num);      }      cout << endl;      return 0;  }
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 考上博士但是硕士要延期怎么办 硕士延期也不能毕业怎么办 硕士论文工作量太少被延期了怎么办 竞彩足球比赛延期中断怎么办? 竞彩足球输了怎么办 讯飞语音不兼容百度怎么办 虎牙直播不兼容语音怎么办 为什么手机打开游戏就死机怎么办 2007cad打开时时死机怎么办 手机qq总是无响应怎么办 英雄联盟登录服务器未响应怎么办 苹果7p照相死机怎么办 小米手机qq打不开怎么办啊 电脑qq老是闪退怎么办 微信摄像卡住了怎么办 电脑打开应用程序没反应怎么办 宇飞来手机锁了怎么办 宇飞来手机忘记密码怎么办 vivo手机突然开不了机怎么办 苹果六关不了机怎么办 微信老是无响应怎么办 打游戏被骂了怎么办 微信运动跳转排行榜失败怎么办 小恩爱账号忘了怎么办 华为账号更换后游戏账号怎么办 注册游戏账号需要身份证怎么办 英雄联盟被裁决了怎么办 百度网盘密码重置不了怎么办 sap密码输入被锁怎么办 dnf二级密码错10怎么办 大网卡网速慢了怎么办 小米路由器无线速度慢怎么办 小米手机无线速度慢怎么办 电脑网卡驱动没了怎么办 电脑显示网卡驱动不正常怎么办 微信别人拒收消息怎么办 电脑无线网卡速度慢怎么办 网吧吃鸡更新慢怎么办 手机号注册不了微信怎么办 小米账号密码忘了怎么办 小米手机账号密码忘了怎么办