这道数据结构题怎么做?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了这道数据结构题怎么做?相关的知识,希望对你有一定的参考价值。
待排序的数组为 < 7,4,2,9,8,5,11,3 > ,请分析采用快速排序算法对数组第一趟排序的详细过程。
快速排序是对冒泡排序的一种改进。它的基本思想是:通过一躺排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一不部分的所有数据都要小,然后再按次方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。假设要排序的数组是A[1]……A[N],首先任意选取一个数据(通常选用第一个数据)作为关键数据,然后将所有比它的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一躺快速排序。一躺快速排序的算法是:
1)、设置两个变量I、J,排序开始的时候I:=1,J:=N;
2)以第一个数组元素作为关键数据,赋值给X,即X:=A[1];
3)、从J开始向前搜索,即由后开始向前搜索(J:=J-1),找到第一个小于X的值,两者交换;
4)、从I开始向后搜索,即由前开始向后搜索(I:=I+1),找到第一个大于X的值,两者交换;
5)、重复第3、4步,直到I=J;
例如:待排序的数组A的值分别是:(初始关键数据X:=49)
A[1] A[2] A[3] A[4] A[5] A[6] A[7]:
49 38 65 97 76 13 27
进行第一次交换后: 27 38 65 97 76 13 49
( 按照算法的第三步从后面开始找
进行第二次交换后: 27 38 49 97 76 13 65
( 按照算法的第四步从前面开始找>X的值,65>49,两者交换,此时I:=3 )
进行第三次交换后: 27 38 13 97 76 49 65
( 按照算法的第五步将又一次执行算法的第三步从后开始找
进行第四次交换后: 27 38 13 49 76 97 65
( 按照算法的第四步从前面开始找大于X的值,97>49,两者交换,此时J:=4 )
此时再执行第三不的时候就发现I=J,从而结束一躺快速排序,那么经过一躺快速排序之后的结果是:27 38 13 49 76 97 65,即所以大于49的数全部在49的后面,所以小于49的数全部在49的前面。
快速排序就是递归调用此过程——在以49为中点分割这个数据序列,分别对前面一部分和后面一部分进行类似的快速排序,从而完成全部数据序列的快速排序,最后把此数据序列变成一个有序的序列,根据这种思想对于上述数组A的快速排序的全过程如图6所示:
初始状态 49 38 65 97 76 13 27
进行一次快速排序之后划分为 27 38 13 49 76 97 65
分别对前后两部分进行快速排序 13 27 38
结束 结束 49 65 76 97
49 65 结束
结束
图6 快速排序全过程
1)、设有N(假设N=10)个数,存放在S数组中;
2)、在S[1。。N]中任取一个元素作为比较基准,例如取T=S[1],起目的就是在定出T应在排序结果中的位置K,这个K的位置在:S[1。。K-1]<=S[K]<=S[K+1..N],即在S[K]以前的数都小于S[K],在S[K]以后的数都大于S[K];
3)、利用分治思想(即大化小的策略)可进一步对S[1。。K-1]和S[K+1。。N]两组数据再进行快速排序直到分组对象只有一个数据为止。
如具体数据如下,那么第一躺快速排序的过程是:
数组下标: 1 2 3 4 5 6 7 8 9 10
45 36 18 53 72 30 48 93 15 36
I J
(1) 36 36 18 53 72 30 48 93 15 45
(2) 36 36 18 45 72 30 48 93 15 53
(3) 36 36 18 15 72 30 48 93 45 53
(4) 36 36 18 15 45 30 48 93 72 53
(5) 36 36 18 15 30 45 48 93 72 53
通过一躺排序将45放到应该放的位置K,这里K=6,那么再对S[1。。5]和S[6。。10]分别进行快速排序。
一般来说,冒泡法是程序员最先接触的排序方法,它的优点是原理简单,编程实现容易,但它的缺点就是--程序的大忌--速度太慢。下面我介绍一个理解上简单但编程实现上不是太容易的排序方法,我不知道它是不是现有排序方法中最快的,但它是我见过的最快的。排序同样的数组,它所需的时间只有冒泡法的 4% 左右。我暂时称它为“快速排序法”。
“快速排序法”使用的是递归原理,下面我结合一个例子来说明“快速排序法”的原理。首先给出一个数组53,12,98,63,18,72,80,46, 32,21,先找到第一个数--53,把它作为中间值,也就是说,要把53放在一个位置,使得它左边的值比它小,右边的值比它大。21,12,32, 46,18,53,80,72,63,98,这样一个数组的排序就变成了两个小数组的排序--53左边的数组和53右边的数组,而这两个数组继续用同样的方式继续下去,一直到顺序完全正确。
我这样讲你们是不是很胡涂,不要紧,我下面给出实现的两个函数:
/*
n就是需要排序的数组,left和right是你需要排序的左界和右界,
如果要排序上面那个数组,那么left和right分别是0和9
*/
void quicksort(int n[], int left,int right)
int dp;
if (left<right)
/*
这就是下面要讲到的函数,按照上面所说的,就是把所有小于53的数放
到它的左边,大的放在右边,然后返回53在整理过的数组中的位置。
*/
dp=partition(n,left,right);
quicksort(n,left,dp-1);
quicksort(n,dp+1,right); //这两个就是递归调用,分别整理53左边的数组和右边的数组
我们上面提到先定位第一个数,然后整理这个数组,把比这个数小的放到它的左边,大的放右边,然后
返回这中间值的位置,下面这函数就是做这个的。
int partition(int n[],int left,int right)
int lo,hi,pivot,t;
pivot=n[left];
lo=left-1;
hi=right+1;
while(lo+1!=hi)
if(n[lo+1]<=pivot)
lo++;
else if(n[hi-1]>pivot)
hi--;
else
t=n[lo+1];
n[++lo]=n[hi-1];
n[--hi]=t;
n[left]=n[lo];
n[lo]=pivot;
return lo;
这段程序并不难,应该很好看懂,我把过程大致讲一下,首先你的脑子里先浮现一个数组和三个指针,第一个指针称为p指针,在整个过程结束之前它牢牢的指向第一个数,第二个指针和第三个指针分别为lo指针和hi指针,分别指向最左边的值和最右边的值。lo指针和hi指针从两边同时向中间逼近,在逼近的过程中不停的与p指针的值比较,如果lo指针的值比p指针的值小,lo++,还小还++,再小再++,直到碰到一个大于p指针的值,这时视线转移到hi指针,如果 hi指针的值比p指针的值大,hi--,还大还--,再大再--,直到碰到一个小于p指针的值。这时就把lo指针的值和hi指针的值做一个调换。持续这过程直到两个指针碰面,这时把p指针的值和碰面的值做一个调换,然后返回p指针新的位置。 参考技术A 假设要排序的数组是A[0]……A[N-1],首先任意选取一个数据(通常选用第一个数据)作为关键数据,然后将所有比它的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一躺快速排序。一躺快速排序的算法是:
1)、设置两个变量I、J,排序开始的时候I:=0,J:=N-1;
2)以第一个数组元素作为关键数据,赋值给X,即X:=A[0];
3)、从J开始向前搜索,即由后开始向前搜索(J:=J-1),找到第一个小于X的值,两者交换;
4)、从I开始向后搜索,即由前开始向后搜索(I:=I+1),找到第一个大于X的值,两者交换;
5)、重复第3、4步,直到I=J;
我们看一下:
A[0] A[1] A[2] A[3] A[4] A[5] A[6] A[7]
7 4 2 9 8 5 11 3
1、i=0,j=7
2、X=7
3、从j=7向前找,A[7]<X,A[7]与A[0]交换,j=6
A[0] A[1] A[2] A[3] A[4] A[5] A[6] A[7]
3 4 2 9 8 5 11 7
4、从i=0向后找,A[3]>X,A[7]与A[3]交换,i=1
A[0] A[1] A[2] A[3] A[4] A[5] A[6] A[7]
3 4 2 7 8 5 11 9
5、从j=6向前找,A[5]<X,A[3]与A[5]交换,j=5
A[0] A[1] A[2] A[3] A[4] A[5] A[6] A[7]
3 4 2 5 8 7 11 9
6、从i=1向后找,A[4]>X ,A[4]与A[5]交换,i=2
A[0] A[1] A[2] A[3] A[4] A[5] A[6] A[7]
3 4 2 5 7 8 11 9
7、从j=5向前找,A[3]<X,A[3]与A[4]交换,j=4
A[0] A[1] A[2] A[3] A[4] A[5] A[6] A[7]
3 4 2 7 5 8 11 9
8、从i=2向后找,i=3,没有
A[0] A[1] A[2] A[3] A[4] A[5] A[6] A[7]
3 4 2 7 5 8 11 9
9、从j=4向前找,,j=3,没有
A[0] A[1] A[2] A[3] A[4] A[5] A[6] A[7]
3 4 2 7 5 8 11 9
10、此时i=j,结束第一趟交换。
看着算法自己理解,欢迎批评指正。
楼主也也可以自己从网上查一下这个算法,也有例题可以参考。本回答被提问者和网友采纳 参考技术B 楼上那位把整个理论与实现都搬过来了...够壮观,我就针对这题给你讲一下吧,假设数组A表示为:
无 7 4 2 9 0 5 11 3 ......值
-1 0 1 2 3 4 5 6 7 ......索引号
i,j key ......初始时三个变量的初始位置,置于是指针还是啥,随意
经典快排思想如下
1:首先选取最后一个值作为键值,即将key变量指向A[7];
2:初始化遍历用的变量i,j为-1,即数组开头的前面一位;其中i是当前所遍历的数值,j+1是当前遍历过的所有数值中序号最小的比key值大的数值的索引号
3:开始从0-6逐个遍历数组:
i=0:a[0] = 7,>a[key],即发现第一个大于key值的值,j不变
i=1:a[1] = 4,>a[key],发现第二个大于key的值,j不变
i=2:a[2] = 2,<a[key],发现小于key值得值,将其与目前所知道的数值大于key中索引号最小的值交换位置,即a[j+1]=a[0],然后将j重新指向索引最小的比key值大的数,j++即j=0;
序列第一次发生变化:2 4 7 9 0 5 11 3 然后继续遍历
i=3:a[3] = 9,>a[key],j不变
i=4:a[4] = 0, <a[key],同i=2时的操作之后
序列第二次发生变化:2 0 7 9 4 5 11 3 此时j++后j=1
i=5:a[5] = 5,不变
i=6:a[6] = 11,不变
i=key:遍历结束,将key值与当前比其大的数值中索引最小的值交换,即a[j+1]=a[2]
序列第三次发生变化:2 0 3 9 4 5 11 7
返回j+1,即2,完成第一次排序,所作的事情就是将比a[2]=3小的值全放到其左边,比其大的值全在右边,所以位于a[2]的值的序号就是最终序号
楼上那位是选的a[0]作为key,不过原理是一样的,你可以结合一起来看,他就是把所有比a[3]=7小的放其左边,其余右边
leetcode 双周赛 Biweekly Contest 6
最后一题比赛快结束的时候想到怎么做了(通过WA的数据猜出来的),比赛后10分钟做出来的。最终做了3题,时间1个小时左右吧。
1150. Check If a Number Is Majority Element in a Sorted Array
这道题理论应该用二分,但是数据量很小(1000),所以就直接暴力过了:
class Solution public: bool isMajorityElement(vector<int>& nums, int target) int count = 0; for(int i = 0;i < nums.size();i++) if(nums[i] == target) count++; else if(nums[i] > target) break; return count > (nums.size() / 2); ;
1151 Minimum Swaps to Group All 1‘s Together
这道题是滑动窗口题。找到包含最少0的窗口(窗口长度等于数组里1的个数)
class Solution public: int minSwaps(vector<int>& data) int count = 0; int n = data.size(); for(int i = 0;i < n;i++) if(data[i] == 1) count++; int begin = 0; int zeros = 0; int res = INT_MAX; for(int i = 0;i < n;i++) // end int len = i - begin + 1; if(len > count) if(data[begin] == 0) zeros--; begin++; len = count; if(data[i] == 0) zeros++; if(len == count) res = min(res, zeros); return res; ;
1152. Analyze User Website Visit Pattern
这道题可能是哈希和排序吧。WA了三次才过(有一次是没看清楚WA的点在哪,为了看错误点又提交了一次)。写的非常恶心。但是每次我洋洋洒洒写完100行的答案,总能在评论区看见10行搞定的 = =
class Solution public: vector<string> get(const string& s) string str; vector<string> res; for(int i = 0;i < s.size();i++) if(s[i] != ‘ ‘) str.push_back(s[i]); else res.push_back(str); str.clear(); return res; bool IsSmaller(const string& s1, const string& s2) vector<string> res1 = get(s1); vector<string> res2 = get(s2); for(int i = 0;i < res1.size();i++) if(res1[i] == res2[i]) continue; return res1[i] < res2[i]; return false; struct message string username; int timestamp; string website; message() message(string& u, int& t, string& w) : username(u), timestamp(t), website(w) friend bool operator<(const message& m1, const message& m2) return m1.timestamp < m2.timestamp; ; vector<string> mostVisitedPattern(vector<string>& username, vector<int>& timestamp, vector<string>& website) unordered_map<string, int> count; int n = username.size(); vector<message> msg(n); for(int i = 0;i < n;i++) msg[i] = message(username[i], timestamp[i], website[i]); sort(msg.begin(), msg.end()); unordered_map<string, vector<string>> web; for(int i = 0;i < n;i++) web[msg[i].username].push_back(msg[i].website); for(auto& w : web) string name = w.first; vector<string>& site = w.second; if(site.size() < 3) continue; unordered_set<string> unique; for(int i = 0;i < site.size(); i++) for(int j = i + 1; j < site.size(); j++) for(int k = j + 1;k < site.size(); k++) string str = site[i] + " " + site[j] + " " + site[k] + " "; if(unique.find(str) == unique.end()) count[str]++; unique.insert(str); int maxtimes = 0; vector<string> res; string maxstr; for(auto& c : count) int times = c.second; if(times > maxtimes) maxtimes = times; maxstr = c.first; else if(times == maxtimes) if(IsSmaller(c.first, maxstr)) maxstr = c.first; return get(maxstr); ;
1153. String Transforms Into Another String
这道题首先不能一对多,存在就返回错误。然后如果存在转换存在闭环,如:
abc -> bca
相当于转换为a -> b -> c -> a,形成了一个回路,这种情况是可以转换的,因为可以借助不是abc的一个字符作为桥梁。
但是如果闭环涵盖了26个小写字符,那么就没办法找到桥梁了,返回false。最终相当于判断所有形成闭环的字符是不是为26。(以上都是我从WA的答案中得到提示,才想到的
总感觉求闭环数写的不是太对,我的方法是访问到已经访问过的字符后,把两个访问下标相减得到环路大小的,(我刚刚编的方法)。但是勉勉强强也AC了:
class Solution public: vector<int> visit; vector<int> graph; int res = 0; int count = 0; void dfs(int i) // find a loop if(visit[i] != -1) res += count - visit[i]; return; visit[i] = count; if(graph[i] != -1) count++; dfs(graph[i]); bool canConvert(string str1, string str2) if(str1 == str2) return true; int n = str1.size(); graph.resize(26, -1); for(int i = 0;i < n;i++) if(graph[str1[i] - ‘a‘] != -1 && graph[str1[i] - ‘a‘] != str2[i] - ‘a‘) return false; graph[str1[i] - ‘a‘] = str2[i] - ‘a‘; int count = 0; visit.resize(26, -1); for(int i = 0;i < 26;i++) if(visit[i] == -1) count = 0; dfs(i); if(res == 26) return false; return true; ;
以上是关于这道数据结构题怎么做?的主要内容,如果未能解决你的问题,请参考以下文章