1、把序列中的正负数分开
举例:
序列:0,2,-1,4,-2,-3,6,7,-9,10
处理好的序列:-9 -3 -1 -2 4 2 6 7 0 10
注意:
仅仅把正负数分开就好,正数和负数里面不要求次序
不要求排序,这里遍历一遍序列就可以了,时间复杂度为O(n)
//应用一:把序列中的正负数分开算法
#include <iostream>
using namespace std;
const int len = 10;
void Divide(int arr[],int n);
int main()
{
int arr[len]={0,2,-1,4,-2,-3,6,7,-9,10};
//int arr[len]={1,2,1,4,2,3,6,7,9,10};
Divide(arr,len);
for (int i=0;i<len;i++)
{
cout<<arr[i]<<" ";
}
system("pause");
}
/*进行一次快速排序即可*/
void Divide(int arr[],int n)
{
int temp;
int low=0;
int high = n-1;
while (low<high)
{
while (low<high && arr[low]<0)
{
low++;
}
while (low < high && arr[high]>=0)
{
high--;
}
if (low < high)//满足此式时,表示遇到了arr[low]指向正数,但是arr[high]指向负数的情况,这时需要互换元素
{
temp = arr[low];
arr[low]=arr[high];
arr[high]=temp;
//互换后,low和high位置已经处理完毕,这时下标要往前移动一位---不要忘了啊
low++;
high--;
}
}
}
2、查找第j小的元素
//应用二:查找第j小的元素
#include <iostream>
using namespace std;
const int len =10000;
template<class T>
T QSort(T arr[],int n,int j);
template<class T>
int Partition(T arr[],int low,int high);
int main()
{
int arr[len];
for (int i=0;i<len;i++)
{
arr[i]=rand()%100;
}
cout<<"第"<<7<<"个数为:"<<QSort(arr,len,6)<<endl;
system("pause");
return 0;
}
template<class T>
T QSort(T arr[],int n,int j)
{
int low = 0;
int high = n-1;
int keyLoc = Partition(arr,low,high);
while (keyLoc != j)
{
if (keyLoc > j)
{
keyLoc = Partition(arr,low,keyLoc-1);
}
else
{
keyLoc = Partition(arr,keyLoc+1,high);
}
}
return arr[j];
}
template<class T>
int Partition(T arr[],int low,int high)
{
T key = arr[low];
while (low < high)
{
while (low < high && arr[high] >= key)
{
high--;
}
arr[low] = arr[high];
while (low<high && key >= arr[low])
{
low++;
}
arr[high] = arr[low];
}
arr[low] = key;
return low;
}
3、荷兰国旗
//应用三:荷兰国旗
//思想:可以视为数组的排序问题,这个数组可以分为 前部 中部和后部,当前边和后面拍好后,数组自动排好了
//具体思路:
//前提:使用j进行对数组进行遍历,i指向红色区,k指向蓝色区--(j左边和k右边的元素全被处理过)
//效果:0 - i-1:红色 i - k-1:白色 k - n-1:蓝色
//1、j遍历到的位置为1(红)时,说明它一定在前部,
// 则直接和i进行交换即可,这里i始终指向以确定白色位置的下一位,并且i和j均想前走一步(++)
//2、j遍历到的位置为2(白)时,说明它一定在中部,
// 则该元素不动,j向先走一步,处理下一个位置
//3、j遍历到的位置为3(蓝)时,说明它一定在后部,
// 则直接和k进行交换,这里k始终指向确定是蓝色位置的前一位(倒着走的),这时k应--,但是此时j不能向前走,
// 刚换过来的元素是还没处理过的,这时j往前走,就会把该元素忽略(j左边和k右边的元素全被处理过)
//这里一直担心的问题是,出现“22211”时怎么处理:见2时往前走,见到第一个1时,应该和第一个2交换,这时1就和2换位置了,刚刚可以满足题意
#include <iostream>
using namespace std;
const int len = 10;
void FlagAdjust(int arr[],int n);
void Show(int arr[],int n);
int main()
{
int arr[len];
for (int i=0;i<len;i++)
{
arr[i]=rand()%3 + 1;
}
Show(arr,len);
FlagAdjust(arr,len);
Show(arr,len);
system("pause");
return 1;
}
void FlagAdjust(int arr[],int n)
{
int i=0;
int j=0;
int k=n-1;
int temp;
while (j<k)
{
if (arr[j]==1)//红色
{
temp =arr[i];
arr[i]=arr[j];
arr[j]=temp;
i++;
j++;
}
else if (arr[j]==2)//2代表白色
{
j++;
}
else//3代表蓝色
{
temp=arr[j];
arr[j]=arr[k];
arr[k]=temp;
k--;
}
}
}
void Show(int arr[],int n)
{
for (int i=0;i<len;i++)
{
switch (arr[i])
{
case 1:
cout<<"红";
break;
case 2:
cout<<"白";
break;
case 3:
cout<<"蓝";
break;
}
}
cout<<endl;
}
4、快排的非递归程序,这里是固定选择枢轴的版本
/*快排的非递归代码*/
#include <iostream>
using namespace std;
const int len = 10;
struct node
{
int low;
int high;
};
void QSort(int arr[],int n);
int main()
{
int arr[len];
for (int i=0;i<len;i++)
{
arr[i]=rand()%100;
}
//排序前结果
for (int i=0;i<len;i++)
{
cout<<arr[i]<<" ";
}
cout<<endl;
//快速排序
QSort(arr,len);
//排序后结果
for (int i=0;i<len;i++)
{
cout<<arr[i]<<" ";
}
cout<<endl;
system("pause");
return 1;
}
void QSort(int arr[],int n)
{
int top=-1;
struct node stack[len];
int low =0;
int high=0;
top++;
stack[top].low = 0;
stack[top].high = n-1;
while (top>-1)
{
//出栈
low = stack[top].low;
high = stack[top].high;
top--;
while (low < high)
{
//这里引入first和low的原因:low和high在下面的一次快排中会发生变化,
//而根据最终枢轴位置还要把原数据分成两段,这时需要记录本次待排序数据长度的首尾下标
int first = low;
int last = high;
//一次快排
int key = arr[low];
while (low<high)
{
while (high > low && arr[high] > key)
{
high--;
}
arr[low]=arr[high];
while (high > low && arr[low] < key)
{
low++;
}
arr[high] = arr[low];
}
arr[low]=key;
//枢轴把数据分成两段,这时需要把这两段待排序的两下标都放入栈中,之后进行依次出栈进行排序
//枢轴左半段入栈
top++;
stack[top].low = first;
stack[top].high = low -1;
//枢轴右半段入栈
top++;
stack[top].low = low+1;
stack[top].high = last;
}
}
}