데이터 구조: 정렬 알고리즘 총화

11731 단어 DataStruct
상용 정렬 알고리즘 시공 복잡 도 및 안정성:
정렬 알고리즘
시간 복잡 도 평균 상황
시간 복잡 도 최 적 상황
시간 복잡 도 최 악의 경우
보조 공간
안정성
거품 정렬
O(n^2)
O(n)
O(n^2)
O(1)
안정시키다
정렬 선택
O(n^2)
O(n^2)
O(n^2)
O(1)
불안정
삽입 정렬
O(n^2)
O(n)
O(n^2)
O(1)
안정시키다
힐 정렬
O(n^2)~O(n*log(n))
O(n)
O(n^2)
O(1)
불안정
더미 정렬
O(n*log(n))
O(n*log(n))
O(n*log(n))
O(1)
불안정
정렬
O(n*log(n))
O(n*log(n))
O(n*log(n))
O(n)
안정시키다
빠 른 정렬
O(n*log(n))
O(n*log(n))
O(n^2)
O(log(n))~O(n)
불안정
거품 정렬:
      선형 표 의 거품 정렬 은 이중 순환 으로 교체 하 는 방식 을 사용 하고 정렬 방식 은 큰 것 에서 작은 것 으로 내부 순환 은 매번 최대 수 에서 정렬 할 수 있 는 표 까지 나 오 며 외부 순환 은 현재 정렬 할 수 있 는 표 의 길 이 를 제어 합 니 다.이 과정 은 마치 물 속 의 기포 가 튀 어 나 오 는 과정 처럼 작은 기포 가 아래 에서 위로 튀 어 나 오 는 과정 에서 점점 커지 고 마지막 에 큰 기포 가 수면 위로 튀 어 나온다.
알고리즘 프로 세 스: (큰 것 에서 작은 것 으로 정렬 하고 뒤로 옮 겨 다 니 기)
1. 매번 앞 뒤 두 개의 수 를 옮 겨 다 니 며 앞의 수가 뒤의 수 보다 작은 두 개의 수 를 교환 하 는 위 치 를 만난다.
2. 한 번 순환 이 끝나 면 다음 순환 의 길 이 는 1 로 줄어든다.
3. 전체 배열 을 옮 겨 다 닐 때 까지.
#include "sort.h"

vector popSort(vector& src)
{
	int n = src.size();
	for (int i = 0; i < n; ++i)
	{
		for (int j = 0; j < n - i - 1; ++j)
		{
			if (src[j] < src[j + 1])
				SWAP(src[j], src[j + 1]);
		}
	}
	return src;
}

개 선 된 거품 정렬:
       거품 이 발생 하 는 과정 에 대해 정렬 (큰 것 에서 작은 것 으로 정렬) 을 하고 표를 옮 겨 다 니 는 과정 에서 왼쪽 에서 오른쪽으로 옮 겨 다 니 는 과정 에서 최소 값 이 표 꼬리 까지 나 오고 오른쪽 끝 표 시 는 왼쪽으로 한 명 미 끄 러 지 며 오른쪽 에서 왼쪽으로 옮 겨 다 니 는 과정 에서 가장 큰 값 이 표 머리 까지 나 오고 왼쪽 표 시 는 오른쪽으로 한 명 미 끄 러 집 니 다.마지막 왼쪽 끝 에 표 시 된 것 이 오른쪽 끝 에 표 시 된 것 과 같 을 때 까지.
알고리즘 프로 세 스:
1. 왼쪽 에서 오른쪽으로 선형 표를 옮 겨 다 니 며 앞 뒤 데 이 터 를 비교 하고 왼쪽 데이터 가 오른쪽 시간 보다 두 개의 데 이 터 를 바 꾸 면 오른쪽 표지 가 끝 날 때 까지 오른쪽 표지 가 왼쪽으로 한 자 리 를 이동 합 니 다.
2. 오른쪽 표지 에서 왼쪽 표지 로 옮 겨 다 니 며 앞 뒤 데 이 터 를 비교 하고 왼쪽 데이터 가 오른쪽 시간 보다 두 개의 데 이 터 를 바 꾸 면 왼쪽 표지 가 끝 날 때 까지 왼쪽 표 시 는 오른쪽으로 한 자 리 를 이동 합 니 다.
3. 왼쪽 끝 표시 가 오른쪽 끝 표시 와 같 을 때 정렬 이 끝 납 니 다.
#include "sort.h"

vector advancePopSort(vector& src)
{
	int left = 0, right = src.size() - 1;
	while (left < right)
	{
		for (int i = left; i < right; ++i)
		{
			if (src[i] < src[i + 1])
				SWAP(src[i], src[i + 1]);
		}
		right--;
		for (int j = right; j > left; --j)
		{
			if (src[j] > src[j - 1])
				SWAP(src[j], src[j - 1]);
		}
		left++;
	}
	return src;
}

정렬 선택:
       데이터 배열 은 큰 것 부터 작은 것 까지 정렬 을 선택 하고 선형 표 에서 정렬 을 선택 하 는 기본 사상 은 한 무더기 의 데이터 에서 가장 큰 숫자 와 헤더 의 데 이 터 를 선택 하여 바 꾼 다음 에 나머지 숫자 에서 두 번 째 큰 숫자 와 헤더 에서 시작 하 는 두 번 째 수 를 선택 하여 바 꾸 는 것 이다. 이에 따라 전체 표를 옮 겨 다 닐 때 까지 아래로 내 려 가 는 것 이다.
알고리즘 프로 세 스:
1. 데 이 터 를 반복 해서 옮 겨 다 니 며 가장 큰 데이터 와 현재 헤더 위치의 수 를 찾 아 바 꿉 니 다.
2. 교환 이 완료 되면 표 머리 는 정렬 된 다음 숫자 로 표 시 됩 니 다.
3. 표 의 모든 데이터 가 질서 가 있 을 때 까지.
#include "sort.h"

//     :
vector seekSort(vector& src)
{
	int n = src.size();
	for (int i = 0; i < n - 1; ++i)
	{
		int pos = -1, max = src[i];
		for (int j = i + 1; j < n; ++j)
		{
			if (max < src[j])
			{
				max = src[j];
				pos = j;
			}
		}
		if (pos != -1)
			SWAP(src[i], src[pos]);
	}

	return src;
}

//     :
vector selectSort(vector& src)
{
	int n = src.size();
	for (int i = 0; i < n - 1; ++i)
	{
		int min = i;
		for (int j = i + 1; j < n; ++j)
		{
			if (src[j] > src[min])
				min = j;
		}
		if (min != i)
		{
			SWAP(src[i], src[min]);
		}
	}

	return src;
}

삽입 정렬:
       선형 표 의 삽입 정렬, (큰 것 에서 작은 것 까지) 정렬 을 삽입 하 는 기본 적 인 사 고 는 하나의 숫자 부터 질서 있 게 보고 다음 숫자 를 취한 다 는 것 이다. 만약 에 횟수 가 첫 번 째 숫자 보다 작 으 면 첫 번 째 수의 뒤에 횟수 를 꽂 고 반대로 첫 번 째 수 를 한 자리 뒤로 옮 기 고 첫 번 째 수 앞 에 횟수 를 꽂 으 면 두 개의 수 를 포함 하 는 서열 을 구성한다.그 다음 에 세 번 째 수 를 꺼 내 고 서열 이 있 는 위 치 를 옮 겨 다 니 며 적당 한 삽입 위 치 를 찾 아 삽입 한 후의 수 를 전체적으로 한 자리 뒤로 옮 깁 니 다.전체 표 의 데이터 가 다 취 소 될 때 까지 이렇게 숫자 를 삽입 합 니 다.
알고리즘 프로 세 스:
1. 숫자 를 취 하 는 과정 은 두 번 째 숫자 부터 시작한다.
2. 적당 한 위 치 를 찾 아 위 치 를 뒤로 이동 합 니 다.
3. 표 의 데 이 터 를 모두 꺼 낼 때 까지.
#include "sort.h"

vector insertSort(vector& src)
{
	int n = src.size();

	for (int i = 1; i < n; ++i)
	{
		int temp = src[i], pos = -1;
		for (int j = i - 1; j >= 0; --j)
		{
			if (src[j] < temp)
			{
				pos = j;
			}
		}
		if (pos != -1)
		{
			for (int k = i; k > pos; --k)
			{
				src[k] = src[k - 1];
			}
			src[pos] = temp;
		}
	}

	return src;
}

힐 정렬:
       선형 표 는 힐 정렬 을 한다. (큰 것 에서 작은 것 까지) 힐 정렬 은 그 라 데 이 션 보폭 의 삽입 정렬 이다. 처음에 보폭 이 크 면 첫 번 째 정렬 과정 에서 서열 이 상대 적 으로 질 서 를 확보 할 수 있다. 그 다음 에 걸음 길 이 를 줄 이 고 다음 순 서 는 부분 적 인 조정 만 하면 걸음 길이 가 1 이 될 때 약간 조정 하면 정렬 이 끝난다.
알고리즘 프로 세 스:
1. 보폭 을 선택 하고 정렬 을 삽입 합 니 다.
2. 보폭 을 줄 여 정렬 을 삽입 합 니 다.
#include "sort.h"

vector shellSort(vector& src)
{
	int n = src.size();
	for (int step = n / 2; step > 0; step /= 2)
	{
		for (int i = step; i < n; ++i)
		{
			for (int j = i - step; j + step < n; j += step)
			{
				if (src[j] > src[j + step])
					SWAP(src[j], src[j + step]);
			}
		}
	}
	return src;
}

더미 정렬:
       쌓 기 순 서 는 이 진 트 리 의 확률 을 이용 하여 큰 지붕 더미 와 작은 지붕 더 미 를 구성 하 는 것 이다. 큰 지붕 더미 에서 모든 나무 뿌리 노드 의 수 치 는 항상 좌우 노드 보다 크 거나 같 으 며 작은 지붕 더 미 는 반대로 뿌리 노드 의 수 치 는 모두 좌우 노드 보다 작다.그러나 선형 표를 쌓 아 정렬 할 때 쌓 아 올 릴 필요 가 없다. 즉, 이 진 트 리 를 구축 할 필요 가 없다.질 서 는 규칙 을 적용 해 야 한다.
/ / 아래 에 i 로 표 시 된 노드 는 왼쪽 잎 노드 의 아래 표 시 는 2i + 1 이 고 오른쪽 잎 노드 아래 표 시 는 2i + 2 / / 큰 지붕 더미: a [i] > = a [2 * i + 1] & a [i] > = a [2 * i + 2];
/ / 작은 지붕 더미: a [i] < = a [2 * i + 1] & & a [i] < = a [2 * i + 2];
따라서 매번 서열 에 대해 큰 지붕 더미 나 작은 지붕 더 미 를 조정 할 때마다 최대 수 나 최소 수 를 얻 을 수 있 고 횟수 를 더미 에서 선형 표 의 끝 을 분리 한 다음 에 나머지 수 를 조정 하여 모든 수 를 질서 있 게 조정 할 수 있다.
#include "sort.h"

//   i              2i + 1,         2i + 2
//   :a[i] >= a[2 * i + 1] && a[i] >= a[2 * i + 2];
//   :a[i] <= a[2 * i + 1] && a[i] <= a[2 * i + 2];

void adjustHeep(vector& src, int end)
{
	for (int i = end / 2; i >= 0; --i)
	{
		if (2 * i + 2 <= end && src[i] > src[2 * i + 2])
		{
			SWAP(src[i], src[2 * i + 2]);
		}
		if (2 * i + 1 <= end && src[i] > src[2 * i + 1])
		{
			SWAP(src[i], src[2 * i + 1]);
		}
	}
}

vector heepSort(vector& src)
{
	for (int i = src.size() - 1; i > 0; --i)
	{
		adjustHeep(src, i);
		SWAP(src[0], src[i]);
	}
	return src;
}

병합 정렬:
       병합 정렬 사상 은 데이터 구 조 를 처음 배 웠 을 때 항상 하 는 데이터 구조 문제 와 유사 하 다. 두 개의 질서 있 는 서열 을 하나의 질서 있 는 서열 로 합 친다.따라서 무질서 한 서열 을 정리 하고 정렬 하면 그 과정 은 재 귀 작업 과 결합 하여 진행 하기 쉽다.재 귀적 으로 깊이 들 어 가 는 과정 에서 필요 하지 않 은 서열 을 하나의 단독 수 로 나 누고 단독 수 는 질서 있 는 것 으로 간주 하 며 재 귀적 으로 거 슬러 올 라 가 는 과정 에서 이런 단독 수 를 1 대 1 로 합 쳐 서열 로 만 들 고 최종 적 으로 큰 질서 있 는 서열 로 합 친다.
#include "sort.h"

vector& mergeStep(vector& src, int af, int at, int bf, int bt)
{
	vector a(src.begin() + af, src.begin() + at + 1);
	vector b(src.begin() + bf, src.begin() + bt + 1);

	size_t i = 0, j = 0;
	while (i < a.size() && j < b.size())
	{
		if (a[i] < b[j])
		{
			src[af] = a[i];
			i++;
		}
		else
		{
			src[af] = b[j];
			j++;
		}
		af++;
	}

	if (i < a.size())
	{
		for (; i < a.size(); ++i)
		{
			src[af++] = a[i];
		}
	}

	if (j < b.size())
	{
		for (; j < b.size(); ++j)
		{
			src[af++] = b[j];
		}
	}
	return src;
}

vector& mergerSort(vector& src, int left, int right)
{
	if (left >= right)
		return src;

	int mid = (left + right) / 2;
	mergerSort(src, left, mid);
	mergerSort(src, mid + 1, right);
	mergeStep(src, left, mid, mid + 1, right);
}

빠 른 정렬:
       빠 른 정렬 사상 은 매번 무질서 한 서열 에서 하나의 기 수 를 찾 아 서열 을 구분 하고 기수 보다 큰 수 는 한쪽 에 두 고 기수 보다 작은 수 는 다른 쪽 에 두 는 것 이다.다음 에 기수 양쪽 의 무질서 한 수 를 나 누 어 그 중에서 기 수 를 찾 아 구분 하면 기 수 를 선택 한 후에 양쪽 에 숫자 가 없어 서 빠 른 정렬 이 끝 납 니 다.
       그 공간 복잡 도 는 O (1) 이기 때문에 한 단위 의 보조 공간 이 기수 의 값 을 저장 해 야 하기 때문에 대 비 를 시작 하 는 방향 은 서열 에서 기수 에 비해 다른 쪽 이다. 예 를 들 어 왼쪽 에서 기 수 를 취하 면 비 교 를 시작 할 때 취 하 는 수 는 서열 의 오른쪽 에서 시작 하여 이렇게 교환 하 는 것 이다.
       기수 정렬 을 선택 하 는 과정 에서 끝 나 는 표 지 는 왼쪽 위치 표시 가 오른쪽 위치 표시 와 같은 값 입 니 다.어 릴 때 부터 크게 정렬 하면 기수 보다 작은 것 은 왼쪽 에 놓 고 기수 보다 큰 것 은 오른쪽 에 놓는다.
#include "sort.h"
#include 


//vector         ,                   
vector& quickSort(vector& src, int left, int right) 
{
	if (left >= right)
		return src;

	int l = left;
	int r = right;
	int temp = src[left];
	while (l < r)
	{
		while (l < r && src[r] >= temp)
		{
			r--;
		}
		src[l] = src[r];
		while (l < r && src[l] <= temp)
		{
			l++;
		}
		src[r] = src[l];
	}//r == l
	src[l] = temp;
	quickSort(src, left, l - 1);
	quickSort(src, r + 1, right);
}


//       :
int seek(vector&src, int l, int r)
{
	int index = l;
	int temp = src[l];
	while (l < r)
	{
		while (l < r && src[r] <= temp)
		{
			r--;
		}
		src[l] = src[r];
		while (l < r && src[l] >= temp)
		{
			l++;
		}
		src[r] = src[l];
	}//l == r
	src[l] = temp;
	index = l;
	return index;
}
//       :
vector& quickSort(vector& src)
{
	size_t index = seek(src, 0, src.size() - 1);
	stack range;
	if (index - 1 > 0)//       
	{
		range.push(0);
		range.push(index - 1);
	}
	if (index + 1 < src.size() - 1) //       
	{
		range.push(index + 1);
		range.push(src.size() - 1);
	}

	while (!range.empty())
	{
		size_t right = range.top();
		range.pop();
		size_t left = range.top();
		range.pop();

		index = seek(src, left, right);

		if (index - 1 > left)
		{
			range.push(left);
			range.push(index - 1);
		}

		if (index + 1 < right)
		{
			range.push(index + 1);
			range.push(right);
		}
	}

	return src;
}

관련 내용:
        위 글 에 사 용 된 헤더 파일 sort. h
#pragma once

#include 
#include 
using namespace std;

#define SWAP(a, b) a^=b^=a^=b

        위의 main 함수
#include "sort.h"

extern vector advancePopSort(vector&);
extern vector seekSort(vector&);
extern vector selectSort(vector&);
extern vector insertSort(vector& src);
extern vector& quickSort(vector& src, int left, int right);
extern vector shellSort(vector& src);
extern vector& mergerSort(vector& src, int left, int right);
extern vector heepSort(vector& src);
extern vector& quickSort(vector& src);

void showResult(const vector& src)
{
	typedef vector::const_iterator vi_itr;
	for (vi_itr itr = src.begin(); itr != src.end(); ++itr)
	{
		cout << *itr << " ";
	}
	cout << endl;
}

int main()
{
	int buf[] = { 2, 3, 1, 7, 5, 8, 4, 3, 6 };

	//vector sort_buff = insertSort(vector(buf, buf + 9));
	/*vector sort_buff(buf, buf + 9);
	quickSort(sort_buff, 0, 8);*/

	//vector sort_buff = mergerSort(vector(buf, buf + 9), 0, 8);
	vector sort_buff = shellSort(vector(buf, buf + 9));

	showResult(sort_buff);
}

       C + + 용기 vector 에 사용 되 는 정렬 알고리즘 은 빠 른 정렬 알고리즘 이지 만 정렬 과 정렬 을 삽입 하여 이 루어 집 니 다.
       알고리즘 의 안정성 이란 같은 수가 정렬 전후 에 상대 적 인 위 치 를 유지 하고 안정 적 인 정렬 알고리즘 을 위해 그렇지 않 으 면 불안정한 정렬 알고리즘 을 말한다.

좋은 웹페이지 즐겨찾기