데이터 구조의 매력 을 느끼다: 검색 성능 최적화
8392 단어 데이터 구조
문제 배경
하나의 함 수 는 수신 메시지 부하 에 있 는 요 소 를 그룹 으로 나 눈 다음 에 이 요 소 를 그룹 단위 로 보 내야 합 니 다.한 이미지 의 예 를 들 어 한 택배 회 사 는 화물 택배 효율 을 높이 기 위해 전국 각 도시 에서 각 환 승 역 의 직통 선 로 를 개통 했다.한 차 의 소포 가 A 지 중계 역 에 도착 하면 A 지 의 중계 역 은 즉시 이 소 포 를 선별 한 후 화물 목적 도시 에 따라 차 를 나 누 어 환 적 할 수 있다.이 문제 의 배경 은 '택배 환 승 소 에서 소포 에 대한 선별, 환 적 절차' 와 같다. 나 누 어 보면 이 절 차 는 대체적으로 다음 과 같은 세 부분 을 포함한다.
// 、 、 group ,
// group
PacketGroupType g_PacketGroups[MAX_PROVINCE_NUM][MAX_CITY_NUM][MAX_TOWN_NUM];
// group
void PacketsGrouping(void *msg)
{
PacketsCarrierMsgType *pMsg = (PacketsCarrierMsgType *) GetPayloadFromMsy(msg);
packetsNum = pMsg->number;
for (int i = 0; i <packetsNum; i ++ )
{
PacketsType packet = pMsg->packets[i];
int provinceNo = GetProvinceNo(&packet);
int cityNo = GetCityNo(&packet);
int townNo = GetTownNo(&packet);
g_PacketGroups[provinceNo][cityNo][townNo].elemsNum++;
AddPacketIntoGroup(packet, &g_PacketGroups[provinceNo][cityNo][townNo]);
}
...
}
// group , 0 ,
void PacketsSending(void *msg)
{
...
for (int i = 0; i < MAX_PROVINCE_NUM; i ++)
{
for (int j = 0; j < MAX_CITY_NUM; j ++)
{
for (int k = 0; k < MAX_TOWN_NUM; k ++)
{
if (g_PacketGroups[i][j][k].elemsNum != 0)
{
SendPacketGroup(&g_PacketGroups[i][j][k]);
}
}
}
}
...
}
태그 비트 사용 하기
위의 이러한 실현 방안 은 현재 도착 한 소포 의 수량 이 얼마 가 되 든 최종 적 으로 몇 group 로 나 뉘 든 모두 하나씩 g 를 옮 겨 다 녀 야 합 니 다.Packet Groups 의 모든 group 은 의미 없 는 작업 을 많이 했 습 니 다.첫 번 째 간단 한 최 적 화 를 시작 할 수 있 습 니 다. 표시 위 치 를 사용 하여 발송 시의 검색 효율 을 높 일 수 있 습 니 다.자세 한 것 은 소포 수가 0 이 아 닌 group 에 표시 위 치 를 설정 하고 표시 위치 에 다른 추가 정 보 를 인 코딩 하여 불필요 한 검색 을 피 하 는 것 입 니 다.다음 과 같다.
//
unsigned char g_ElementInGroupFlag[MAX_PROVINCE_NUM][MAX_CITY_NUM][MAX_TOWN_NUM];
// “ group”
// g_ElementInGroupFlag[0][0][0] 4 0 g_ElementInGroupFlag[0][0] , MAX_TOWN_NUM ;
// g_ElementInGroupFlag[0][1][0] 4 0 g_ElementInGroupFlag[0][1] , MAX_TOWN_NUM ;
...
// “ group”
// g_ElementInGroupFlag[1][0][0] 4 0 g_ElementInGroupFlag[0] , MAX_TOWN_NUM*MAX_CITY_NUM ;
// g_ElementInGroupFlag[2][0][0] 4 0 g_ElementInGroupFlag[1] , MAX_TOWN_NUM*MAX_CITY_NUM ;
// , 。
void PacketsGrouping(void *msg)
{
PacketsCarrierMsgType *pMsg = (PacketsCarrierMsgType *) GetPayloadFromMsy(msg);
packetsNum = pMsg->number;
for (int i = 0; i <packetsNum; i ++ )
{
PacketsType packet = pMsg->packets[i];
int provinceNo = GetProvinceNo(&packet);
int cityNo = GetCityNo(&packet);
int townNo = GetTownNo(&packet);
g_ElementInGroupFlag[provinceNo][cityNo][townNo] = 1;
g_ElementInGroupFlag[provinceNo][cityNo][0] |= 1 << 4;
g_ElementInGroupFlag[provinceNo][0][0] |= 1 << 4;
g_PacketGroups[provinceNo][cityNo][townNo].elemsNum++;
AddPacketIntoGroup(packet, &g_PacketGroups[provinceNo][cityNo][townNo]);
}
...
}
void PacketsSending(void *msg)
{
...
for (int i = 0; i < MAX_PROVINCE_NUM; i ++)
{
if (g_ElementInGroupFlag[i][0][0] != 1)
{
continue;
}
for (int j = 0; j < MAX_CITY_NUM; j ++)
{
if (g_ElementInGroupFlag[provinceNo][j][0] != 1)
{
continue;
}
for (int k = 0; k < MAX_TOWN_NUM; k ++)
{
if (g_ElementInGroupFlag[i][j][k] != 0)
{
SendPacketGroup(&g_PacketGroups[provinceNo][cityNo][townNo]);
}
}
}
}
...
}
이렇게 하 는 것 은 효율 이 좀 높 지만, 매우 보기 흉 하 다.특히 여기 if... contine... 매크로 를 사용 하여 최적화 할 수 있 습 니 다.
#define CONTINU_IF(EXPR) \
if (EXPR) \
{\
continue; \
}\
용기 의 방법
표기 위치의 최적화 방법 은 전체 효율 에 확실히 개선 되 었 지만, 여전히 매우 부족 하 다.더 나 아가 용 기 를 사용 하 는 것 을 고려 하여 group 을 용기 로 하 는 요소 에 따라 용기 에 추가 하고 소 포 를 보 낼 때 용 기 를 직접 옮 겨 다 니 면 됩 니 다.
// 、 、 group
PacketGroupType g_PacketGroups[MAX_PROVINCE_NUM][MAX_CITY_NUM][MAX_TOWN_NUM];
PacketGroupType g_PacketGroupContainer[MAX_PROVINCE_NUM * MAX_CITY_NUM * MAX_TOWN_NUM];
// group
void PacketsGrouping(void *msg)
{
PacketsCarrierMsgType *pMsg = (PacketsCarrierMsgType *) GetPayloadFromMsy(msg);
packetsNum = pMsg->number;
for (int i = 0; i <packetsNum; i ++ )
{
PacketsType packet = pMsg->packets[i];
int provinceNo = GetProvinceNo(&packet);
int cityNo = GetCityNo(&packet);
int townNo = GetTownNo(&packet);
g_PacketGroups[provinceNo][cityNo][townNo].elemsNum++;
AddPacketIntoGroup(packet, g_PacketGroups[provinceNo][cityNo][townNo]);
if (g_PacketGroups[provinceNo][cityNo][townNo] is not in g_PacketGroupContainer)
{
AddGroupPacketIntoContainer(g_PacketGroups[provinceNo][cityNo][townNo], g_PacketGroupContainer);
}
}
...
}
// group , group
void PacketsSending(void *msg)
{
...
for (group in g_PacketGroupContainer)
{
SendPacketGroup(group);
}
...
}
현재 코드 는 DSP 의 각 core 에서 실행 되 며 메모리 관리 가 엄격 하여 STL 용기 의 기본 메모리 분배 기 를 직접 사용 할 수 없 기 때문에 라 이브 러 리 에 있 는 용 기 를 사용 하지 않 습 니 다.이 방안 은 이미 비교적 이상 적 인 방안 이지 만 싫어 하 는 '무 거 운 제거' 작업 은 정말 큰 흠 이 라 처리 하기 어렵다.
교묘 한 링크 기법
용기 의 방안 은 이미 상당히 OK 이지 만, 더욱 효율 적 인 방법 이 있다!위의 용기 의 방법 에 비해 이런 방법 은 두 가지 장점 이 있다.
// 、 、 group
PacketGroupType g_PacketGroups[MAX_PROVINCE_NUM][MAX_CITY_NUM][MAX_TOWN_NUM];
PacketGroupManager g_PacketGroupManager;
typedef strunct PacketGroupInfo{
int provinceNo;
int cityNo;
int townNo;
PacketGroupInfo *next;
boolean isInGroupManager;
}
typedef strunct{
PacketGroupInfo *head;
PacketGroupInfo groupsInfo[MAX_PROVINCE_NUM][MAX_CITY_NUM][MAX_TOWN_NUM];
}PacketGroupManager;
// group
void PacketsGrouping(void *msg)
{
PacketsCarrierMsgType *pMsg = (PacketsCarrierMsgType *) GetPayloadFromMsy(msg);
packetsNum = pMsg->number;
for (int i = 0; i <packetsNum; i ++ )
{
PacketsType packet = pMsg->packets[i];
int provinceNo = GetProvinceNo(&packet);
int cityNo = GetCityNo(&packet);
int townNo = GetTownNo(&packet);
g_PacketGroups[provinceNo][cityNo][townNo].elemsNum++;
AddPacketIntoGroup(packet, g_PacketGroups[provinceNo][cityNo][townNo]);
if (g_PacketGroupManager.groupsInfo[provinceNo][cityNo][townNo].isInGroupManager == 0)
{
AddGroupIntoManager(g_PacketGroups[provinceNo][cityNo][townNo], g_PacketGroupManager);
}
}
...
}
// group Manager , group
void PacketsSending(void *msg)
{
...
for (PacketGroupInfo *pItem = g_PacketGroupManager.head; pItem != NULL; pItem = pItem->next)
{
SendPacketGroup(pItem );
}
...
}
이러한 방안 의 특수성 은 기 존의 group 저장 구조 와 대응 되 지만 필요 한 정보 만 포함 하 는 경량급 관리 구 조 를 사용 하 는 동시에 정적 링크 방식 으로 조건 을 만족 시 키 는 group 정 보 를 유지 하고 노드 의 배분 과 방출 작업 을 추가 로 수행 하지 않 는 다 는 것 이다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
정수 반전Udemy 에서 공부 한 것을 중얼거린다 Chapter3【Integer Reversal】 (예) 문자열로 숫자를 반전 (toString, split, reverse, join) 인수의 수치 (n)가 0보다 위 또는 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.