这很快,非常感谢,成功了,有没有办法将两个节点作为一个整体交换?就像创建一个临时节点一样,将 i 保存在该节点中等等? –
艾哈迈德·萨布蒂
要交换整个结构内容,请将交换代码替换为:
LNode temp = *i;
*j = *i;
*j = temp;
编辑: 但是......正如约翰在下面指出的那样,上述内容还不够。我们必须保留链接。我们可以只是逐个元素地复制链接除了,但最简单的方法是复制整个结构,但保存/恢复链接:
// preserve the link pointers
LNode *temp_i = i->next;
LNode *temp_j = j->next;
// swap all contents
LNode temp = *i;
*j = *i;
*j = temp;
// restore the link pointers
i->next = temp_i;
j->next = temp_j;
由于您的排序性质,您正在交换整个结构内容。这很好,但如果你的结构中包含(例如)int array[1000000];,它就不会很好地扩展。
但是,链表非常适合归并排序。这样,您可以交换链接。
这里有一些用于链接列表的归并排序代码。它是我拥有的更大库的一部分,因此无法直接编译。
它对列表和节点使用单独的结构。
因为它来自我的个人收藏,所以我有自己的约定。 slh_p 是一个指向列表结构的指针。 slk_p 是一个指向元素结构的指针。
它可能会给你一些想法:
// ovrlib/sls -- singly linked list sort
#include <ovrlib/slk.h>
#include <stdio.h>
// _slhsort -- sort list
void
_slhsort(slh_p slh,slkcmp_p cmp)
{
// NOTE: this is a separate routine so we can add the code below for a
// doubly linked list
_slhsortgo(slh,cmp);
#if 0
slk_p prev;
slk_p cur;
// do final fixup of back chain pointers
// FIXME/CAE -- doing a single pass here is _probably_ faster than doing
// it in the merge step [only to toss it away]
prev = NULL;
for (cur = slh->slh_head; cur != NULL; cur = cur->slk_next) {
cur->slk_prev = prev;
prev = cur;
}
#endif
}
// _slhsortgo -- sort list
void
_slhsortgo(slh_p slhi,slkcmp_p cmp)
{
slh_t slhlhs;
slh_t slhrhs;
do {
// trivial case (i.e. empty list or list with _single_ element)
if (slhi->slh_curcnt < 2)
break;
// split the list
_slhsortspl(slhi,&slhlhs,&slhrhs);
// sort left half
_slhsortgo(&slhlhs,cmp);
// sort right half
_slhsortgo(&slhrhs,cmp);
// merge them
_slhsortmrg(slhi,&slhlhs,&slhrhs,cmp);
} while (0);
}
// _slhsortspl -- split up list
void
_slhsortspl(slh_p slhi,slh_p slhlhs,slh_p slhrhs)
{
slhoff_t lhscnt;
slk_p cur;
slk_p prev;
slk_p next;
// NOTE: we leave slhi's slh_curcnt intact as it is invariant across the
// merge
// get the split point
lhscnt = slhi->slh_curcnt;
lhscnt /= 2;
// set the counts
slhlhs->slh_curcnt = lhscnt;
slhrhs->slh_curcnt = slhi->slh_curcnt - lhscnt;
// NOTES:
// (1) because we're doing half the list and the list has at least two, we
// _know_ "cur" will _never_ be null
// (2) the loop _must_ execute at least _once_
// (3) thus, we know that "prev" will be non-null at the end
// (4) and, we know that "next" will be _valid_ at the end
prev = NULL;
for (cur = slhi->slh_head; lhscnt > 0; --lhscnt, cur = next) {
next = cur->slk_next;
prev = cur;
}
// finish the left list:
// (1) set the head
// (2) set the tail
// (3) break the chain pointer to the right half
slhlhs->slh_head = slhi->slh_head;
slhlhs->slh_tail = prev;
prev->slk_next = NULL;
// finish the right list:
// (1) set the head
// (2) set the tail
slhrhs->slh_head = next;
slhrhs->slh_tail = slhi->slh_tail;
}
// _slhsortmrg -- merge the two halves
void
_slhsortmrg(slh_p slho,slh_p slhlhs,slh_p slhrhs,slkcmp_p cmp)
{
slk_p cur;
slk_p lhs;
slk_p rhs;
slk_p prev;
slk_p tail;
int stopflg;
lhs = slhlhs->slh_head;
rhs = slhrhs->slh_head;
prev = NULL;
stopflg = 0;
// NOTE: we are guaranteed to execute this once, so we always set the head
// and we will always have a non-null "prev" value
while (1) {
// stop when [at least] one of the lists runs dry
if (stopflg)
break;
// left list element is lower
if (cmp(lhs,rhs) <= 0) {
cur = lhs;
lhs = lhs->slk_next;
stopflg = (lhs == NULL);
}
// right list element is lower
else {
cur = rhs;
rhs = rhs->slk_next;
stopflg = (rhs == NULL);
}
// set the output list head
if (prev == NULL)
slho->slh_head = cur;
// append to the output list
else
prev->slk_next = cur;
// remember the previous/last element we added to the output list
prev = cur;
}
// select the remainder (i.e. the non-empty list)
// there will be only one, at most, and we can have none
do {
cur = NULL;
// left list has all remaining higher values
if (lhs != NULL) {
cur = lhs;
tail = slhlhs->slh_tail;
break;
}
// right list has all remaining higher values
if (rhs != NULL) {
cur = rhs;
tail = slhrhs->slh_tail;
break;
}
// both lists have been exhausted [equally]:
// (1) nothing more to append
// (2) we already know the tail
tail = prev;
} while (0);
// append the remainder to the output list
prev->slk_next = cur;
// set the tail of the output list
// the tail's next pointer is already null
slho->slh_tail = tail;
}
这里是相关的.h 文件:
// ovrlib/slk.h -- singly linked list control
#ifndef _ovrlib_slk_h_
#define _ovrlib_slk_h_
#include <ovrinc/ovrtypes.h>
#include <ovrinc/ovrinl.h>
#include <ovrinc/ovrstruct.h>
#include <ovrinc/ovrptr.h>
CDEFBEGIN
typedef long slhoff_t; // dynamic array offset
#define _SLKDEF(_typ) \
u32 slk_stat; /* status */ \
TYP_P(_typ) slk_next /* link to next element */
#define SLKDEF(_typ) \
_MSTRUCT(_typ)
#define SLH_P(_typa) \
TYP_P(_typa)
#define SLK_P(_typ) \
TYP_P(_typ)
#define SLHDEFX(_typa,_typ) \
MFORWARD(_typ); \
MFORWARD(_typa); \
_MSTRUCT(_typa) { \
u32 slh_stat; /* status */ \
slhoff_t slh_itmsiz; /* item size */ \
slhoff_t slh_grow; /* number of elements to grow */ \
TYP_P(_typa) slh_pool; /* free pool chain pointer */ \
const char *slh_tag; /* list name */ \
/**/ \
TYP_P(_typ) slh_head; /* head pointer */ \
TYP_P(_typ) slh_tail; /* tail pointer */ \
/**/ \
slhoff_t slh_curcnt; /* current active count */ \
/**/ \
void (*slh_yldproc)(TYP_P(_typa)); /* yield subroutine */ \
void *slh_yldptr; /* yield control */ \
int slh_yldchunk; /* yield chunk control */ \
}
#define SLHYLDPROC(_slh,_proc) \
typeof(_slh->slh_yldproc) _proc = _slh->slh_yldproc
#define SLHDEF(_typ) \
SLHDEFX(_typ,_typ)
// generic definition
SLHDEFX(slh,slk);
SLKDEF(slk) {
_SLKDEF(slk);
void *slk_xtra; // link to data
};
// initialize for yield loop
#define YLDCNTINIT(_slh,_yldcnt) \
do { \
if (_slh->slh_stat & SLHDONE) { \
_yldcnt = 0; \
break; \
} \
_yldcnt = _slh->slh_yldchunk; \
if (_yldcnt != 0) \
break; \
_yldcnt = -1; \
} while (0)
// bump down yield count
#define YLDCNTINC(_yldcnt) \
if (_yldcnt > 0) \
--_yldcnt
#define SLKALLOC (1u << 31) // allocated item
#define SLHPOOL (1u << 30) // list is free pool
#define SLHINITED (1u << 29) // list is inited
#define SLHDONE (1u << 28) // list is done
#define SLHDIRTY (1u << 27) // list is "dirty"
#define SLH(_vp) CAST(slh_p,_vp)
#define SLK(_vp) CAST(slk_p,_vp)
#define slhsetup(_slh,_siz,_grow) VP(_slhsetup(SLH(_slh),_siz,_grow))
#define slhattach(_pool,_slh) _slhattach(SLH(_pool),SLH(_slh))
#define slhgrow(_slh) _slhgrow(SLH(_slh))
#define slknew(_slh) VP(_slknew(SLH(_slh)))
#define slkrls(_slh,_slk) _slkrls(SLH(_slh),SLK(_slk))
#define slkpush(_slh,_pnew) VP(_slkpush(SLH(_slh),SLK(_pnew)))
#define slkshift(_slh,_slk) VP(_slkshift(SLH(_slh),SLK(_slk)))
#define slhrls(_slh) _slhrls(SLH(_slh))
#define slhkill(_slh) _slhkill(SLH(_slh))
#define slhsort(_slh,_cmp) _slhsort(SLH(_slh),_cmp)
typedef int (*slkcmp_p)(const void *,const void *);
// simple forward scan
#define SLHFORALL(_slh,_slk) \
CASTEQ(_slk,_slh->slh_head); _slk != NULL; CASTEQ(_slk,_slk->slk_next)
// shift forward scan
#define SLHFORALL_SHIFT(_slh,_slk) \
_slk = slkshift(_slh,NULL); _slk != NULL; _slk = slkshift(_slh,NULL)
// shift forward scan
#define SLHFORALL_SHIFT_RELEASE(_slh,_slk) \
_slk = slkshift(_slh,NULL); _slk != NULL; _slk = slkshift(_slh,_slk)
// continuation forward scan
#define _SLHFORALL(_slh,_slk) \
; _slk != NULL; CASTEQ(_slk,_slk->slk_next)
#include <ovrlib/slk.proto>
CDEFEND
#endif