您的位置:首页 > 理论基础 > 数据结构算法

【数据结构】:排序--交换排序

2017-02-28 22:48 148 查看

交换排序

1、基本思想

思想的核心是“交换”,是指借助序列中元素之间的相互交换进行排序的方法。

2、种类

冒泡排序

快速排序

冒泡排序

1、基本思想

抓住两个点:趟数和次数

对于冒泡排序,一个元素要经过多少趟才能冒出头,其他的元素要经过同样的形式多少次。

2、代码实现

基本实现

void BubbleSort(int*a, size_t sz)
{
int i = 0;
int j = 0;
int temp = 0;
int sz = sizeof(arr)/sizeof(arr[0]);
for(i = 0; i<sz-1; i++)     //表示要排多少趟
{
for(j = 0; j<sz-i-1; j++)  //表示每一趟要比较多少次
{
if(arr[j] < arr[j+1])
{
flag = 1;
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}

}


优化实现

1)优化1:加标志位

说明:我们来想一种极端的情况:如果这个序列原本就是排好序的,那么也要经过N^2/2次,因为我们不知道它是排好序的,所以此处的优化就是加一个标志位,在内循环中,如果发现已经排好序了,就可以跳出了。

代码实现:

void BubbleSort(int*a, size_t sz)
{
int i = 0;
int j = 0;
int temp = 0;
int flag = 1;
int sz = sizeof(arr)/sizeof(arr[0]);
for(i = 0; i<sz-1; i++)     //表示要排多少趟
{
flag = 0;   //加标记进行优化
for(j = 0; j<sz-i-1; j++)  //表示每一趟要比较多少次
{
if(arr[j] < arr[j+1])
{
flag = 1;
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
if(flag == 0)
break;
}


2)优化2:

说明:我们再想象一种极端情况:array长度为n,但是只有0,1元素未排序,那么依照上一种优化算法我们依然要遍历2*n次。原因在于我们内层循环长度的设定依据是,i次排序array的后i-1个元素是排序好的,但实际上i次排序的循环长度取决于i-1次排序时最后的交换位置,例如i-1次排序的最后交换位置是index,则表明index之后的元素都已经排序完毕,我们只需要记录这个Index就得到了下次(i次)的循环长度。

代码实现:

void BubbleSort(int*a, size_t sz)
{
int i = 0;
int j = 0;
int temp = 0;
int flag = 1;
int index = 0;
int mark = sz-1;//用于记录前i-1个元素排好序后的下标
int sz = sizeof(arr)/sizeof(arr[0]);
for(i = 0; i<sz-1; i++)     //表示要排多少趟
{
flag = 0;   //加标记进行优化
for(j = 0; j<mark; j++)  //表示每一趟要比较多少次
{
if(arr[j] < arr[j+1])
{
flag = 1;
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
index = j;
}
}
if(flag == 0)
break;
mark = index;
}
}


3、时间复杂度

最好的情况是:O(N)

最坏的情况:O(N^2)

快速排序

1、基本思想

它其实是对冒泡排序的一种改进,首先任意选取一个数据(通常选用第一个数据)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序。然后两部分的数据再分别进行快速排序,可以用递归进行实现。

2、快排如何实现

划分的三种方法

1)左右指针法

*说明:



*代码实现(后附)

2)挖坑法

*说明:



*代码实现:(后附)

3)前后指针法

*说明:



*代码实现:(后附)

-  优化的两种方法
- 1)三数取中法
*说明:
我们如果取得数是接近这组数中的中间值的话,那么进行排序的时候效率就大大的上去了
*代码实现 :


int GetMidIndex(int* a,int left,int right)
{
int mid = left+ ((right-left)>>1);

if(a[left] < a[mid])
{
if(a[right] > a[mid])
return mid;

else if(a[left] < a[right])
return right;

return left;
}
else
{
if(a[left]< a[right])
return left;

else if(a[mid] < a[right])
return right;

else
return mid;
}

}


- 2)小区间优化
*说明:
我们在进行递归实现其他部分的时候,当数据比较小的时候,我们可以使用直接插入法来进行排序,这时就免去了递归时压栈等等的一些开销。
*代码实现:


void QuickSort(int* a,int left, int right)
{

if(right-left < 20)
{
Insert(a+left,a+right-1);
}
else{

if(left < right)
{
int div = PartSort(a,left,right);
QuickSort(a,left,div-1);
QuickSort(a,div+1,right);
}
}
}


3非递归实现快速排序

说明:

使用栈来实现

代码实现:

void QuickSortNonR(int* a,int left, int right)
{
stack<int> s;
s.push(right);
s.push(left);
while(!s.empty())
{
int begin = s.top(); //此时取得数是left;
s.pop();
int end = s.top();  //此时取得数是right
s.pop();

int div = PartSort(a,begin,end);
//begin, div+1
//div-1,end
if(begin < div1)
{
s.push(div-1);
s.push(begin);
}
if(end > div-1)
{
s.push(end);
s.push(div-1);

}

}

}


4、快排的递归实现

void QuickSort(int* a,int left, int right)
{
//加入小区间优化
if(right-left < 20)
{
Insert(a+left,a+right-1);
}
else{

if(left < right)
{
int div = PartSort(a,left,right);
QuickSort(a,left,div-1);
QuickSort(a,div+1,right);
}
}
}


5、快排的时间复杂度

当key为最大或最小的时候是O(N^2)

最好的是O(NlgN)

快排三种划分的代码

1、左右指针法

int PartSort1(int* a, int left,int right)
{
//利用三数取中法进行优化,只做下面的两步就可以
//int key = GetMidIndex(a,left.right);
//swap(a[key],a[right]);

int key = right;
while(left < right)
{
while((left<right) && (a[left] <= a[key]))
left++;

while((left<right) && (a[right] >= a[key]))
right--;

if(a[left] > a[right])
std::swap(a[left],a[right]);

}
std::swap(a[left],a[key]);
return left;
}


2、挖坑法

int PartSort3(int*a, int left,int right)
{
//注意:挖坑法要保存的是要填的值,而不是下标
int key = a[right];
while(left < right)
{
while(left < right && a[left] <= key)
left++;

if(left<right)
a[right] = a[left];

while(left< right && a[right] >= key)
right--;

if(left<right)
a[left]  =a[right];

}
a[left] = key;
return left;
}


3、前后指针法

int PartSort2(int* a, int left,int right)
{
int key = right;
int cur = left;
int pre = cur-1;
while(cur < right)
{
if((a[cur] < a[key]) && (++pre != cur))
swap(a[pre],a[cur]);
++cur;
}
swap(a[++pre],a[right]);
return pre;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: