顺序表中的删除和插入
来源:互联网 发布:vb modbus 编辑:程序博客网 时间:2024/06/16 23:04
顺序表中的运算无非四种,增删改查:
- 增:即向顺序表中插入数据,大部分情况下都是向一个有序表中插入,要是无序的话就先排序。
- 删:删除顺序表中的一个或多个元素,通过数据覆盖来消除原来数据。
- 改:找到数据,修改数据。本质上还是查找。
- 查:用查找算法查找数据。
相信有关于查找的算法大家已经听过很多了,什么折半查找、散列查找之类的。这些查找算法都很经典,所以在网上很容易找到,有时间的话我会总结一下各种查找的方法。今天着重来说一说删除和插入的算法。
先说顺序表的删除算法:
题目1:设数据集合中的数据元素不重复,有一个数据集合A,任意输入一个关键字key,在数据集合中删除数据域值为key的数据。
其实顺序表的删除是比较麻烦的一个算法,删之前还要先查找一番,找到了还要把它后边的元素向前挪,挪完后还要将结尾处处理下。大部分删除都是这个套路,那么我们就按照这个套路来写一遍代码:
void delete(int A[],int key,int& n){ int i,j; for(i=0;i<n&&A[i]-key;i++); //查找key值元素 if(i>=n) cout<<"not found"<<endl; else{ for(j=i;j<n-1;A[j]=A[j+1],j++);//若找到,将该元素后边的值向前覆盖 --n;//数组长度减1 }}
以上为在顺序表中删除一个元素的完整套路。先查找,再覆盖,最后收尾。这是一个最典型的删除例子,也是最简单的。下面我们修改一下题目。
题目2:设数据集合中的数据元素有重复值,有一个数据集合A,任意输入一个关键字key,在数据集合中删除数据域值为key的数据。
分析:这次的难点在于数据元素有重复,可能要删除的元素在数组中有多个。那么假如我们要删除多个元素,能用到的方法是什么呢?按照上题的思路,我们可以先用第一层循环查找到第一个key,然后用第二层循环将key后边的元素前移,接着又回到第一层循环查找到第二个key,再用第二层循环将key后边的元素前移。。。。。。时间复杂度O(n^2),可以解决问题,但是算不得一个高效算法。
可不可以尝试着用一层循环就将所有key值删除呢?我们之所以习惯性的想用两层循环,是因为我们需要在找到一个key值元素并删除后,还能在原位置上继续找。也就是说,需要两个可以指向元素的下标。那么我们的思路就可以这样:
用两个下标i,j来指着这个数组的头元素,要求
- 每比较一个元素i就加1,i指着正在比较的元素。
- 每次比较,i指向的元素值若不为key,j加1;否则j不变。
例如,本次循环中,i和j值相同,都指向一个和key相同的元素,那么下次循环,i加1,j不变,j仍然指向那个待删除的值。那么怎么删除它?直接将i指向的非待删元素覆盖过去就行了。覆盖之后,j指向的元素不为key了,j也就可以继续移动了。有了这个思路,我们就用代码说话:
void delete(int A[],int key,int& n){ int i,j; for(i=j=0;i<n;i++) if(A[i]!=key) //A[i]不为待删元素时,将A[i]赋值给A[j],然后j加1 A[j++]=A[i]; n=j;//j为此时数组元素个数}
还可以再简化:
void delete(int A[],int key,int& n){ int i,j; for(i=j=0;i<n&&(A[i]==key||(A[j++]=A[i],1));i++); /* //(装逼利器)或条件运算符只有在A[i]==key为假时才会执行后边语句; //逗号运算符的结果为逗号后的表达式值,这里是防止数组中有值为0的元素 */ n=j;}
以上的问题中都是要求删除特定值key,那么接下来问点不一样的:
题目3:设数据集合中的数据元素有重复值,有一个数据集合A,元素按升序排列。删除数组中重复的元素。
其实如果理解了上一个题目用到的方法,那么做这道题也不会觉得难。因为这两道题的方法是一样的。
分析:用两个数组下标i,j指向数组头元素,创建一个循环,在循环中,i每次增加1;j只有在i指向的值a与它指向的值b不同时,j加1,然后将a赋值给b。循环结束,j+1为此时数组元素个数。
void delete(int A[],int& n){ int i,j; for(i=j=0;i<n&&(A[i]==A[j]||(A[++j]=A[i],1));i++); n=j+1;}
注意题目2和题目3中的j++和++j:
- 题目2中用j++,是为了删除当前元素,先赋值,再后移。
- 题目3中用++j,是为了删除后边的重复元素(当前元素留着),先后移,再赋值。
如果再有这种题目:
题目4:设数据集合中的数据元素有重复值,有一个数据集合A,元素无序。删除数组中重复的元素。
只需要将数组排序一遍,然后再用题目3的方法解决就好了。关于顺序表的删除我们就告一段落,如果还有别的高效解法我会继续扩充。
再说顺序表的插入算法:
产生插入问题的顺序表一般都是有序表(无序的话就随便插了)。插入的过程应该说是删除的逆过程,它的套路就是:先从后向前找到应该插入的位置(可以在这个过程中把不合适的元素向后移动),再将数值插入,最后收尾。因为在数据插入的时候,插入位置之后的原数据需要向后移动,所以建议查找插入位置时从后向前查找,在查找的同时将元素后移,减少不必要的循环。
举个例子吧:
题目1:有一个数据集合A,元素升序排列。有一个关键字key,将key插入集合,使之仍然有序。
代码:
void insert(int A[],int key,int& n){ int i; for(i=n-1;i>0&&A[i-1]>key;A[i]=A[i-1],i--); A[i]=key;}
这里小心数组越界的情况,除非可以根据上下文明确数组的容量大于n,否则只能将数组最后一个元素覆盖,不能后移。
我们接触的大部分情况下的插入,都是一个数据插入到一个数组中。那么当一个数组需要插入到另一个数组时应该怎么办?
题目2:有数据集合A、B,元素皆升序排列。将两数据集合合并,使之仍然有序。
解法:建立两层循环,第一层选定数组A某一元素,第二层查找B中合适位置将A中元素插入。时间复杂度O(n^2),而且数组越界(额外开辟空间就可以了)。
这种解法并不好,因为时间复杂度还可以再降低。既然已经是升序排列了,那么可以用两个变量指向这两个数组元素,对元素遍历一次的同时进行选择,将选择的数据放入额外的数组C中。
但是另一个问题是,什么时候选择A的元素,什么时候选择B的元素?可以肯定的是,A和B肯定有一个先遍历完。那我们划分一下情况:
一. A没遍历完
1. B没遍历完
(1). A[i]
(2). A[i]>=B[j]: C[k]=B[j];
2. B遍历完
C[k]=A[i];
二. A遍历完
C[k]=B[j]
可以看到根据划分的情况可进行的两种操作。如果将条件合并,就可以在一次遍历中解决问题。
代码:
void combine(int A[m],int B[n],int C[m+n]){ int i=0,j=0,k=0; while(i<m||j<n) { if(j==n||(i<m&&A[i]<B[j]))//该算法相当于根据结果划分情况,再由情况选择执行哪个指令 C[k++]=A[i++]; else C[k++]=B[j++]; }}
- 顺序表中的删除和插入
- 顺序表插入 删除 查找
- 线性表顺序存储结构插入和删除
- 顺序线性表和单链表的插入,删除操作
- c语言实现顺序表的插入,删除和求给定元素在表中的位序等运算
- 顺序表中静态顺序表的创建、插入和删除一个元素(源码分析)
- 顺序表的初始化、删除、插入
- 顺序表基本操作(插入、删除)
- 数据结构之顺序表,插入,删除等
- 顺序表的插入删除java
- 顺序表的插入,删除算法
- 顺序表的创建插入与删除
- 顺序表的初始化、插入、删除
- 顺序表的生成、初始化、插入、删除
- 顺序表 查找 插入 删除 操作
- 顺序表的初始化、插入、删除
- 顺序表插入删除查找操作
- 顺序表的插入与删除
- Mysql设置远程连接
- 归纳笔记05:进度条属性
- 浅谈LTE--为什么EPC选择了sctp?
- 详解PHP处理密码的几种方式
- 跑马灯 代码
- 顺序表中的删除和插入
- Android控件之ScrollView用法实例分析
- Maven实战指南 07
- java并发编程 (一) 《基本知识》
- ChatterBot聊天机器人教程01
- nginx 设置重定向 unknown directive "if($host" in
- Qt Command Prompt命令目录
- ZOJ 2750 Idiomatic Phrases Game 最短路(dijkstra)
- 2016 JAVA与Android面试题整理