数据复习2 - 链表实现。
记得去年我刚才学习到这块的时候, 我有一个朋友给我打电话, 让我帮他做一道链表题, 是一道面试题。 链表冒泡排序。 当时还是懵了下, 好像没听过。回去我就在本子上画, 最后算是搞清了思路。
很简单, 就是用冒泡排序的思想去做。 不过一般的冒泡排序都是使用下标访问到元素的。我们链表这块是不行的。 不过我们可以控制步数, 采用循环,从头节点信息右移到合适的结点。 第二点呢, 对于交换, 我们只是交换结点中val值, 不会真正改变结点的指向。
基于这样的思想, 我们还可以写出二分查找。 把链表当作数组一样操作。
这两接口分别在后面代码中实现。
link.h
#pragma once
/*
project: 单链表(不带头)
time: 2020-6-8
name: HMW
*/
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int Datatype; //重定义int
//结点信息
typedef struct Node
{
Datatype data; //存储数据
struct Node *next; //下一个结点指针
}*LinkNode, Node;
//头结点信息
typedef struct Node_head
{
struct Node *head; //head
}*Node_head, head;
void InitNode(Node_head pHead); //init
void ListPushFront(Node_head pHead, Datatype value); //头插
void ListPopFront(Node_head pHead); //头删
void ListPushBack(Node_head pHead, Datatype value); //尾插
void ListPopBack(Node_head pHead); //尾删
void Print_Link(Node_head pHead); //打印
void Bubble_Sort(Node_head pHead); //冒泡排序
int Binary_Seek(Node_head pHead); //二分查找
void DestoryNode(Node_head pHead); //销毁 - 释放资源
//后面的是链表习题 - 测试
void Deleted_val_Link(Node_head pHead, Datatype val); //删出指定val值结点
Node_head deleteDuplication(Node_head pHead); //删除重复节点
LinkNode Reverse_Link(Node_head pHead); //逆置单链表
Node_head MIddle_Link(Node_head pHead); //中间节点
LinkNode FindKthToTail(Node_head pHead, size_t k); //返回倒数第k个节点
void chkPalindrome(Node_head pHead); //判断是否为回文链表
link.c
#include"link.h"
//初始化链表
void InitNode(Node_head pHead)
{
assert(pHead != NULL);
pHead->head = NULL;
}
//链表的销毁
void DestoryNode(Node_head pHead)
{
if (pHead == NULL)
{
printf("不需要删除,为存入数据\n");
return;
}
LinkNode prev = pHead->head;
LinkNode cur = NULL;
while (prev != NULL)
{
cur = prev->next;
free(prev);
prev = cur;
}
}
//开辟结点
LinkNode Broad_memory(Datatype value)
{
LinkNode p_node = (LinkNode)malloc(sizeof(Node));
if (p_node == NULL)
exit(0);
p_node->data = value;
p_node->next = NULL;
return p_node;
}
//头插
void ListPushFront(Node_head pHead, Datatype value)
{
assert(pHead != NULL);
if (pHead->head == NULL)
{
//链表为空
pHead->head = Broad_memory(value);
}
else
{
LinkNode tmp = Broad_memory(value);
tmp->next = pHead->head;
pHead->head = tmp;
}
}
//尾插
void ListPushBack(Node_head pHead, Datatype value)
{
assert(pHead != NULL);
if (pHead->head == NULL)
{
pHead->head = Broad_memory(value);
}
else
{
LinkNode p_temp = pHead->head;
while (p_temp->next)
{
p_temp = p_temp->next;
}
p_temp->next = Broad_memory(value);
}
}
//头删
void ListPopFront(Node_head pHead)
{
assert(pHead != NULL);
if (!pHead->head)
{
//链表为空
return;
}
else
{
LinkNode tmp = pHead->head->next;
free(pHead->head);
pHead->head = tmp;
}
}
//尾删
void ListPopBack(Node_head pHead)
{
assert(pHead != NULL);
if (!pHead->head)
{
return;
}
else
{
LinkNode cur = pHead->head;
while(cur->next->next)
{
cur = cur->next;
}
free(cur->next);
cur->next = NULL;
}
}
//遍历
void Print_Link(Node_head pHead)
{
assert(pHead != NULL); //
LinkNode p_temp = pHead->head;
printf("---->");
while (p_temp)
{
if(!p_temp->next)
printf("%d", p_temp->data);
else
{
printf("%d->", p_temp->data);
}
p_temp = p_temp->next;
}
printf("\n");
}
//链表长度
int Link_Size(Node_head pHead)
{
int size = 0;
LinkNode tmp = pHead->head;
while (tmp)
{
size++;
tmp = tmp->next;
}
return size;
}
//冒泡排序
void Bubble_Sort(Node_head pHead)
{
assert(pHead != NULL);
int size = Link_Size(pHead);
for (int i = 0; i < size - 1; ++i)
{
int flag = 0;
LinkNode tmp1 = pHead->head;
for (int j = 0; j < size - i - 1; ++j)
{
LinkNode tmp2 = tmp1->next;
if (tmp1->data > tmp2->data)
{
//交换
int swap_value = tmp1->data;
tmp1->data = tmp2->data;
tmp2->data = swap_value;
//优化器
flag = 1;
}
//后移
tmp1 = tmp1->next;
}
if (flag == 0)
{
return;
}
}
}
//二分查找 0 --> 存在 -1 --> 不存在
int Binary_Seek(Node_head pHead, Datatype val)
{
assert(pHead != NULL);
int size = Link_Size(pHead);
int begin = 0;
int end = size - 1;
while (begin <= end)
{
int middle = (end - begin) / 2 + begin;
LinkNode tmp_middle = pHead->head;
LinkNode tmp_begin = pHead->head;
LinkNode tmp_end = pHead->head;
for (int i = 0; i < middle; ++i)
{
tmp_middle = tmp_middle->next;
}
for (int i = 0; i < begin; ++i)
{
tmp_begin = tmp_begin->next;
}
for (int i = 0; i < end; ++i)
{
tmp_end = tmp_end->next;
}
if (tmp_middle->data == val)
{
//找到了
return 0;
}
else if (val < tmp_middle->data)
{
end = middle - 1;
}
else if(val > tmp_middle->data)
{
begin = middle + 1;
}
}
//没有找到
return -1;
}
删除val元素的值
//void Deleted_val_Link(Node_head pHead, Datatype val)
//{
// assert(pHead != NULL);
//
// LinkNode p_temp = pHead->head; //指向头节点
//
// while (p_temp)
// {
// if (p_temp->next) //正常操作!
// {
// if (p_temp->data == val) //等于val的情况
// {
// /*替位操作*/
// LinkNode p = p_temp->next;
// p_temp->data = p->data;
// p_temp->next = p->next;
// free(p);
// p = NULL;
// }
// else
// {
// p_temp = p_temp->next;
// }
// }
// else //尾节点
// {
// if (pHead->head == p_temp) //只有一个节点
// {
// if (p_temp->data == val)
// {
// free(p_temp);
// p_temp = NULL;
// }
// }
// else //不只有一个节点
// {
// if (p_temp->data == val)
// {
// LinkNode p = pHead->head;
// while (p->next != p_temp)
// {
// p = p->next;
// }
// p->next = NULL;
// free(p_temp);
// p_temp = NULL;
// }
// }
// return;
// }
// }
//}
//双指针法
void Deleted_val_Link(Node_head pHead, Datatype val)
{
assert(pHead != NULL);
LinkNode prev = NULL;
LinkNode cur = pHead->head;
while (pHead->head->data == val)
{
pHead->head = pHead->head->next;
}
while (cur)
{
if (cur->data == val)
{
LinkNode p_temp = cur->next;
if (prev != NULL)
{
prev->next = p_temp;
}
free(cur);
cur = p_temp;
}
else
{
prev = cur;
cur = cur->next;
}
}
}
//逆置单链表
LinkNode Reverse_Link(Node_head pHead)
{
if (!pHead)
return NULL;
LinkNode prev, cur, next;
prev = NULL;
cur = pHead->head;
next = pHead->head->next;
while (cur)
{
cur->next = prev;
prev = cur;
cur = next;
if(next!= NULL)
next = next->next;
}
pHead->head = prev;
return prev;
}
//返回中间的节点
Node_head MIddle_Link(Node_head pHead)
{
if (!pHead)
return NULL;
LinkNode slow = pHead->head;
LinkNode fast = pHead->head;
while (fast)
{
if (fast->next != NULL)
fast = fast->next->next;
else
break;
slow = slow->next;
}
pHead->head = slow;
return pHead;
}
//返回倒数第k个节点
LinkNode FindKthToTail(Node_head pHead, size_t k)
{
if (!pHead)
return NULL;
LinkNode slow = pHead->head;
LinkNode fast = pHead->head;
//先走k步
while (k--)
{
if (fast == NULL)
return NULL;
else
fast = fast->next;//证明没有倒数第k个数
}
while (fast)
{
slow = slow->next;
fast = fast->next;
}
return slow;
}
//判断是否为回文链表
void chkPalindrome(Node_head pHead)
{
if (!pHead)
return NULL;
LinkNode B = Reverse_Link(MIddle_Link(pHead));
LinkNode B1 = B;
LinkNode A = pHead->head;
while (B)
{
if (A->data != B->data)
{
printf("不是回文链表!\n");
return;
}
A = A->next;
B = B->next;
}
printf("回文链表!\n");
pHead->head = B1;
Reverse_Link(pHead);
}
//删除重复节点 - 前提: 排序好
Node_head deleteDuplication(Node_head pHead)
{
if (!pHead)
return NULL;
if (!pHead->head)
return NULL;
LinkNode prev = NULL;
LinkNode cur = pHead->head;
LinkNode next = pHead->head->next;
while (next)
{
if (cur->data == next->data)
{
LinkNode p_temp = NULL;
while (next->data == cur->data)
{
p_temp = next->next;
free(next);
next = p_temp;
if (next == NULL)
break;
}
if (prev == NULL)
{
//刚开始就连续, 头节点需要更新
pHead->head = next;
}
else
{
prev->next = next;
}
free(cur);
cur = next;
if (cur != NULL)
{
next = cur->next;
}
else
{
break;
}
}
else
{
prev = cur;
cur = next;
next = next->next;
}
}
return pHead;
}
test.c
#include"link.h"
void test1() {
head pHead;
InitNode(&pHead);
ListPushBack(&pHead, 9);
ListPushBack(&pHead, 8);
ListPushBack(&pHead, 7);
ListPushBack(&pHead, 6);
ListPushBack(&pHead, 5);
ListPushBack(&pHead, 4);
ListPushBack(&pHead, 3);
ListPushBack(&pHead, 2);
Print_Link(&pHead);
Bubble_Sort(&pHead);
printf("冒泡排序!\n");
Print_Link(&pHead);
int ret = Binary_Seek(&pHead, 6);
printf("查找元素6\n");
if (ret == 0)
{
printf("存在\n");
}
else
printf("不存在\n");
DestoryNode(&pHead);
}
int main()
{
//test();
test1();
system("pause");
return 0;
}
测试结果:
这里面我就不测试插入、删除基础接口。 我测试有链表的冒泡排序、二分查找接口, 这里面还有很多链表题的代码, 是我之前做题的时候用这个链表作为测试。
如果有朋友测试出有问题, 希望能指点下我。 谢谢~