您的位置:首页 > 编程语言 > C语言/C++

我面试遇到的C语言中单链表相关的操作粗浅实现

2015-05-16 12:43 471 查看
主要包括单链表中节点的插入, 删除, 反转链表, 链表排序, 查询链表中第几个或倒数第几个节点的值(即将补充的有链表是否有环, 两个链表是否相交以及第一个公共节点). 仅用于备注, 不断更新, 代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

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);
//}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息