c语言中长链表中选出子结点,我面试遇到的C语言中单链表相关的操作粗浅实现...

#include

#include

#include

typedef struct _LinkedNodeTAG {

char value;

struct _LinkedNodeTAG *next;

} LinkedNode;

LinkedNode *new_LinkedNode(char value) {

LinkedNode *pNode;

pNode = (LinkedNode *)malloc(sizeof(LinkedNode));

pNode->value = value;

return pNode;

}

LinkedNode *new_LinkedNode_ex(char value, LinkedNode *next) {

LinkedNode *pNode;

pNode = (LinkedNode *)malloc(sizeof(LinkedNode));

pNode->value = value;

pNode->next = next;

return pNode;

}

void iter_print(LinkedNode *head) {

while (head) {

printf("%c ", head->value);

head = head->next;

}

printf("\n");

}

/* 获取链表上索引位置为index的节点, 需要考虑到链表头节点是否为NULL, 链表是否只有一个节点, 索引是否大于链表的长度. * 这里设定索引从0开始, 索引为正将从头节点向前搜索, 如果为负表示倒数第index个节点, 比如-1表示倒数第一个, 即尾节点. * 求倒数第n个节点的值的思路是使用两个指针从头结点开始一起遍历, 保证指针间隔为n, 第一个指针遍历完时, 后面的指针正好指在倒数第n个节点上 */

LinkedNode *get_node_at(LinkedNode *head, int index) {

if (index >= 0) {/* -0也是0 */

while (index-- > 0 && head) {/* 两个出口, 抵达索引位置或者链表已遍历完(索引位置还未到达) */

head = head->next;

}

return head;

} else {

index = -index;

LinkedNode *node = head;

/* 这里其实可以只用一个循环, 但是每次循环都做判断 */

while (index-- > 0 && head) {

head = head->next;

}

if (index > 0) return NULL;

while (head) {

head = head->next;

node = node->next;

}

return node;

}

}

int remove_node(LinkedNode *head, LinkedNode *node) {

if (!head || !node) return -1;

if (head == node && !head->next) {/* 既是头节点又没有下一个节点, 即只有一个节点 */

free(head);

head = NULL;

return 0;

}

if (head != node && !node->next) {/* 有多个节点, 要删除的可能是尾节点的情况 */

while (head && head->next != node) head = head->next;

if (!head) {/* node可能不在链表上 */

return -1;

} else if (head->next == node) {/* 此时head即为倒数第二个节点 */

head->next = NULL;

free(node);

node = NULL;

}

return 0;

}

/* 有多个节点, 且要删除的不是尾节点的情况, 如果node在另一个链表上, 责任留给调用者. 这里思路是: * 将要删除的节点node的下一个元素的内容value拷贝到要node上, 将node的next指向原下一个元素的next指向的节点, 然后删除原下一个元素节点 */

LinkedNode *next = node->next;

node->value = next->value;

node->next = next->next;

free(next);

next = NULL;

return 0;

}

/* 一个链表, 在node节点前插入inserting节点 */

int insert_node_before(LinkedNode *head, LinkedNode *node, LinkedNode *inserting) {

if (!head || !node || !inserting) return -1;

if (head == node) {

inserting->next = head; /* 链表head节点发生改变 */

return 0;

}

/* 有多个节点, 如果node在另一个链表上, 责任留给调用者. 这里思路是: * 交换node和inserting的内容value, 使原node变成inserting, inserting变成node, 然后node的next原指向的节点由inserting指向, node的next指向inserting */

char temp_value = node->value;

node->value = inserting->value;

inserting->value = temp_value;

inserting->next = node->next;

node->next = inserting;

return 0;

}

/* 首先不断递归进去, 到倒数第二个节点后, 通过next的next, 向前指向前一个节点, 并去掉指向后一个节点但指针 */

LinkedNode *reverse_recusive(LinkedNode *head) {

if (!head || !head->next) return head;

LinkedNode *newHead = reverse_recusive(head->next);

head->next->next = head;

head->next = NULL;

return newHead;

}

LinkedNode *reverse_loop(LinkedNode *head) {

if (!head) return head;

LinkedNode *prev, *next, *remember; /* 使用三个指针 */

prev = head;

next = head->next;

prev->next = NULL; /* 第一个作为尾节点, 置空其next指针 */

while(next) {

remember = next->next; /* 记住下一个的下一个, 以防将下一个但next指向自己以后链表断掉 */

next->next = prev; /* 反转 */

/* 向前移动指针 */

prev = next;

next = remember;

}

return prev;

}

/* 选定一个pivot, 这里是begin, 使用两个指针, big指针往前走, 如果发现指向的值比pivot小, 则向前移动small指针一步, 并交换这两个指针指向的节点内容value. * 这样, small左边到pivot所有节点的内容比pivot指向的节点内容小, 而big左边到small所有节点的内容比pivot指向的节点内容大, 符合了快速排序中一种partition实现思路. * 遍历一遍链表后把pivot指向的节点内容与small指针交换, 保证此时的pivot前面的比它小, 后面的比它大. */

LinkedNode *partition(LinkedNode *begin, LinkedNode *end, LinkedNode *pivot) {

LinkedNode *small, *big;

if (!begin || !pivot) {

return NULL;

}

small = big = begin;

while(big != end) {

if (big->value < pivot->value) {

small = small->next;

char temp = big->value;

big->value = small->value;

small->value = temp;

}

big = big->next;

}

char temp = pivot->value;

pivot->value = small->value;

small->value = temp;

return small;

}

void quick_sort(LinkedNode *begin, LinkedNode *end) {

if (begin != end) {

LinkedNode * pivot = partition(begin, end, begin);

quick_sort(begin, pivot);

quick_sort(pivot->next, end);

}

}

int main(void) {

LinkedNode *head;

LinkedNode *a = new_LinkedNode('e');

LinkedNode *b = new_LinkedNode('f');

LinkedNode *c = new_LinkedNode('b');

LinkedNode *d = new_LinkedNode('a');

LinkedNode *e = new_LinkedNode('d');

LinkedNode *f = new_LinkedNode('g');

LinkedNode *g = new_LinkedNode('c');

a->next = b;

b->next = c;

c->next = d;

d->next = e;

e->next = f;

f->next = g;

g->next = NULL;

head = a;

iter_print(head);

//LinkedNode *node = new_LinkedNode('m');

//insert_node_before(head, c, node);

//iter_print(head);

//remove_node(head, d);

//iter_print(head);

//head = reverse_recusive(head);

//iter_print(head);

//head = reverse_loop(head);

//iter_print(head);

//partition(head, head, NULL, head);

//iter_print(head);

//quick_sort(head, NULL);

//iter_print(head);

//LinkedNode *t = get_node_at(head, -5);

//if (!t) {

// printf("NULL\n");

//} else {

// printf("%c\n", t->value);

//}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值