目录
链表结构
typedef struct node {
int data;
struct node* next;
}NODE;
创建链表
同样采用前插法进行创建(上一篇介绍)
**注意:为避免警告,当申请完内存后,需要判断是否分配成功,使用malloc或者new申请内存时,如果分配失败返回NULL或者nullptr。另外分配失败后注意将链表空间释放。
代码:
NODE* createList(int a[],int len)
{
NODE* head = NULL;
for (int i = len-1; i >= 0; i--)
{
NODE* p = (NODE*)malloc(sizeof(NODE));
if (p == NULL)
{
printf("内存分配失败\n");
freeList(head);
return NULL;
}
p->data = a[i];
p->next = head;
head = p;
}
return head;
}
链表排序
采用归并法进行排序。
排序步骤:
- 对链表进行拆分,直到链表只有一个元素
- 对拆分后的链表按照有序链表合并的方法进行合并
拆分步骤:
- 采用快慢指针法寻找链表的中点
- 按照中点将链表拆分为左右两个链表
寻找链表中点代码:
NODE* midNode(NODE* head)
{
if (!head || !head->next) return head;
NODE* slow = head, * fast=head;
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
排序代码:
NODE* sortList(NODE* head)
{
if (!head || !head->next) return head;
NODE* mid_node = midNode(head);
NODE* right = sortList(mid_node->next);
// 保证左侧链表的最后一个结点的next为NULL
mid_node->next = NULL;
NODE* left = sortList(head);
// 按照有序链表进行排序
return mergeList(left, right);
}
合并有序链表
采用双指针法,分别指向两个有序链表的首元结点。
步骤:
- 创建头结点,并创建临时指针temp指向头结点,时刻指向待插入位置。(临时指针的另一个作用是保证头结点位置不变,保证后续可以根据头结点找到链表)
- 将data小的结点插入到头结点的next,结点后移,temp也需要后移
- 当两个链表有一个为NULL时,将非空的链表直接插入到当前位置的下一个结点。
代码:
NODE* mergeList(NODE* LA, NODE* LB)
{
NODE* LC = (NODE*)malloc(sizeof(NODE));
if (LC == NULL)
{
printf("内存分配失败\n");
free(LC);
return NULL;
}
NODE* temp = LC;
while (LA && LB)
{
if (LA->data < LB->data)
{
temp->next = LA;
LA = LA->next;
}
else {
temp->next = LB;
LB = LB->next;
}
temp = temp->next;
}
// 将非空链表全部插入到当前结点的next
if (LA!=NULL) temp->next = LA;
if (LB!=NULL) temp->next = LB;
return LC->next;
}
打印链表
void printList(NODE* head)
{
while (head)
{
printf("%d->", head->data);
head = head->next;
}
printf("%s\n", "NULL");
}
清除链表
与打印链表的思路一样,传入头结点,只要当前结点非空,便依次释放结点空间。
**注意:需要使用临时结点保存head的下一个结点的信息,防止释放head后,找不到下一个结点。
代码:
void freeList(NODE* head)
{
while (head)
{
// 采用临时指针记录当前结点的下一个结点
NODE* temp = head;
head = head->next;
free(temp);
}
}