一、單向鏈表的概念
單向鏈表是鏈表的一種,其特點是鏈表的鏈接方向是單向的,對鏈表的訪問要通過順序讀取從頭部開始。鏈表是使用指針進行構造的列表,並且是由一個個結點組裝起來的,因此又稱為結點列表。其中每個結點都有指針成員變量指向列表中的下一個結點,head指針指向第一個結點稱為表頭,而終止於最后一個指向nuLL的指針。
結點的數據結構
- typedef struct _LINK_NODE
- {
- int data;
- struct _LINK_NODE* next;
- }LINK_NODE;
typedef struct _LINK_NODE
{
int data;
struct _LINK_NODE* next;
}LINK_NODE;
各個結點連接在一起構成一個單向鏈表(示意圖)

二、單向鏈表的優缺點
和普通的線性結構(如數組)相比,鏈表結構有以下特點:
(1)單個結點創建非常靈活,普通的線性內存通常在創建的時候就需要設定數據的大小
(2)結點的刪除、插入非常方便,不需要像線性結構那樣移動剩下的數據
(3)結點的訪問方便,可以通過循環或者遞歸的方法訪問到任意數據,但是平均的訪問效率低於線性表
三、單向鏈表的基本操作
1、建立一個新的鏈表
- LINK_NODE* create_node(int value)
- {
- LINK_NODE *pLinkNode = NULL;
- pLinkNode = (LINK_NODE *)malloc(sizeof(LINK_NODE));
- pLinkNode->data = value;
- pLinkNode->next = NULL;
- return pLinkNode;
- }
LINK_NODE* create_node(int value)
{
LINK_NODE *pLinkNode = NULL;
pLinkNode = (LINK_NODE *)malloc(sizeof(LINK_NODE));
pLinkNode->data = value;
pLinkNode->next = NULL;
return pLinkNode;
}
2、增加一個結點(增加到末尾)
- int _add_node(LINK_NODE** pNode, LINK_NODE* pDataNode)
- {
- if(NULL == *pNode) {
- *pNode = pDataNode;
- return TRUE;
- }
- return _add_node(&(*pNode)->next, pDataNode);
- }
- int add_node(const LINK_NODE** pNode, int value)
- {
- LINK_NODE *pDataNode;
- if(NULL == *pNode) {
- return FALSE;
- }
- pDataNode = create_node(value);
- if(pDataNode == NULL) {
- return FALSE;
- }
- return _add_node((LINK_NODE**)pNode, pDataNode);
- }
int _add_node(LINK_NODE** pNode, LINK_NODE* pDataNode)
{
if(NULL == *pNode) {
*pNode = pDataNode;
return TRUE;
}
return _add_node(&(*pNode)->next, pDataNode);
}
int add_node(const LINK_NODE** pNode, int value)
{
LINK_NODE *pDataNode;
if(NULL == *pNode) {
return FALSE;
}
pDataNode = create_node(value);
if(pDataNode == NULL) {
return FALSE;
}
return _add_node((LINK_NODE**)pNode, pDataNode);
}
3、刪除一個結點
- int _delete_node(LINK_NODE** pNode, int value)
- {
- LINK_NODE* pLinkNode;
- if(NULL == (*pNode)->next) {
- return FALSE;
- }
- pLinkNode = (*pNode)->next;
- if(value == pLinkNode->data) {
- (*pNode)->next = pLinkNode->next;
- free(pLinkNode);
- return TRUE;
- } else {
- return _delete_node(&(*pNode)->next, value);
- }
- }
- int delete_node(LINK_NODE** pNode, int value)
- {
- LINK_NODE* pLinkNode;
- if(NULL == pNode || NULL == *pNode) {
- return FALSE;
- }
- if(value == (*pNode)->data) {
- pLinkNode = *pNode;
- *pNode = pLinkNode->next;
- free(pLinkNode);
- return TRUE;
- }
- return _delete_node(pNode, value);
- }
int _delete_node(LINK_NODE** pNode, int value)
{
LINK_NODE* pLinkNode;
if(NULL == (*pNode)->next) {
return FALSE;
}
pLinkNode = (*pNode)->next;
if(value == pLinkNode->data) {
(*pNode)->next = pLinkNode->next;
free(pLinkNode);
return TRUE;
} else {
return _delete_node(&(*pNode)->next, value);
}
}
int delete_node(LINK_NODE** pNode, int value)
{
LINK_NODE* pLinkNode;
if(NULL == pNode || NULL == *pNode) {
return FALSE;
}
if(value == (*pNode)->data) {
pLinkNode = *pNode;
*pNode = pLinkNode->next;
free(pLinkNode);
return TRUE;
}
return _delete_node(pNode, value);
}
4、查找結點
- //查找結點,返回數據內容為value的結點地址,沒有找到返回NULL
- LINK_NODE* find_node(const LINK_NODE* pLinkNode, int value)
- {
- if(NULL == pLinkNode)
- return NULL;
- if(value == pLinkNode->data)
- return (LINK_NODE*)pLinkNode;
- return find_node(pLinkNode->next, value);
- }
//查找結點,返回數據內容為value的結點地址,沒有找到返回NULL
LINK_NODE* find_node(const LINK_NODE* pLinkNode, int value)
{
if(NULL == pLinkNode)
return NULL;
if(value == pLinkNode->data)
return (LINK_NODE*)pLinkNode;
return find_node(pLinkNode->next, value);
}
5、統計結點個數
- int count_list(const LINK_NODE *pLinkNode)
- {
- if(NULL == pLinkNode) {
- return 0;
- }
- return 1 + count_list(pLinkNode->next);
- }
int count_list(const LINK_NODE *pLinkNode)
{
if(NULL == pLinkNode) {
return 0;
}
return 1 + count_list(pLinkNode->next);
}
6、打印整個鏈表
- void print_list(const LINK_NODE *pLinkNode)
- {
- if(pLinkNode) {
- printf("%d\n", pLinkNode->data);
- print_list(pLinkNode->next);
- }
- }
void print_list(const LINK_NODE *pLinkNode)
{
if(pLinkNode) {
printf("%d\n", pLinkNode->data);
print_list(pLinkNode->next);
}
}
7、刪除整個鏈表
- void delete_list(LINK_NODE** pNode)
- {
- LINK_NODE** pNext;
- if(NULL == pNode || NULL == *pNode) {
- return ;
- }
- pNext = &(*pNode)->next;
- free(*pNode);
- delete_list(pNext);
- }
void delete_list(LINK_NODE** pNode)
{
LINK_NODE** pNext;
if(NULL == pNode || NULL == *pNode) {
return ;
}
pNext = &(*pNode)->next;
free(*pNode);
delete_list(pNext);
}
8、鏈表逆轉
鏈表逆轉就是把鏈表的方向反過來,頭指針變成尾指針,尾指針變成頭指針,實現草圖如下

a、逆轉並生成新的鏈表(非遞歸方式)
- //新建一條鏈表,新的鏈表是原來鏈表的逆轉,使用while循環實現。
- LINK_NODE *reverse_new_loop(LINK_NODE *head)
- {
- LINK_NODE *p1 = NULL, *p2;
- while(head != NULL)
- {
- p2 = (LINK_NODE *) malloc(sizeof(LINK_NODE));
- if(p1 == NULL) {
- p2->next = NULL;
- } else {
- p2->next = p1;
- }
- p1 = p2;
- p2->data = head->data;
- head = head->next;
- }
- return p1;
- }
//新建一條鏈表,新的鏈表是原來鏈表的逆轉,使用while循環實現。
LINK_NODE *reverse_new_loop(LINK_NODE *head)
{
LINK_NODE *p1 = NULL, *p2;
while(head != NULL)
{
p2 = (LINK_NODE *) malloc(sizeof(LINK_NODE));
if(p1 == NULL) {
p2->next = NULL;
} else {
p2->next = p1;
}
p1 = p2;
p2->data = head->data;
head = head->next;
}
return p1;
}
b、逆轉並生成新的鏈表(遞歸方式)
- //新建一條鏈表,新的鏈表是原來鏈表的逆轉,使用遞歸實現。
- LINK_NODE *reverse_new_recursive(LINK_NODE *head, LINK_NODE *pre)
- {
- LINK_NODE *p = head->next;
- LINK_NODE *new;
- new = (LINK_NODE *) malloc(sizeof(LINK_NODE));
- new->next = pre;
- new->data = head->data;
- if(p) {
- return reverse_new_recursive(p, new);
- } else {
- return new;
- }
- }
//新建一條鏈表,新的鏈表是原來鏈表的逆轉,使用遞歸實現。
LINK_NODE *reverse_new_recursive(LINK_NODE *head, LINK_NODE *pre)
{
LINK_NODE *p = head->next;
LINK_NODE *new;
new = (LINK_NODE *) malloc(sizeof(LINK_NODE));
new->next = pre;
new->data = head->data;
if(p) {
return reverse_new_recursive(p, new);
} else {
return new;
}
}
c、原地逆轉,不生成新鏈表(非遞歸方式)
- //原地逆轉,使用while循環實現。
- LINK_NODE *reverse_local_loop(LINK_NODE *head)
- {
- LINK_NODE *p;
- LINK_NODE *tmp;
- if(NULL == head) {
- return head;
- }
- p = head->next;
- head->next = NULL;
- while(NULL != p) {
- tmp = p->next;
- p->next = head;
- head = p;
- p = tmp;
- }
- return head;
- }
//原地逆轉,使用while循環實現。
LINK_NODE *reverse_local_loop(LINK_NODE *head)
{
LINK_NODE *p;
LINK_NODE *tmp;
if(NULL == head) {
return head;
}
p = head->next;
head->next = NULL;
while(NULL != p) {
tmp = p->next;
p->next = head;
head = p;
p = tmp;
}
return head;
}
d、原地逆轉,不生成新鏈表(遞歸方式)
- //原地逆轉,使用遞歸實現。
- LINK_NODE *reverse_local_recursive(LINK_NODE *head, LINK_NODE *pre)
- {
- LINK_NODE *p = head->next;
- head->next = pre;
- if(p) {
- return reverse_local_recursive(p, head);
- } else {
- return head;
- }
- }
//原地逆轉,使用遞歸實現。
LINK_NODE *reverse_local_recursive(LINK_NODE *head, LINK_NODE *pre)
{
LINK_NODE *p = head->next;
head->next = pre;
if(p) {
return reverse_local_recursive(p, head);
} else {
return head;
}
}
9、鏈表排序
a、選擇排序
選擇排序的基本思想就是反復從還未排好序的那些節點中,選出鍵值最小的節點, 依次重新組合成一個鏈表。可以通過以下三個步驟實現
(1)先在原鏈表中找最小的,找到一個后就把它放到另一個空的鏈表中
(2)空鏈表中存放第一個進來的節點,並且讓它在原鏈表中分離出來
(3)繼續在原鏈表中找下一個最小的,找到后把它放入有序鏈表的尾指針的next,然后它變成其尾指針
- //選擇排序,從小到大。
- LINK_NODE *SelectSort(LINK_NODE *head)
- {
- LINK_NODE *first; /*排列后有序鏈的表頭指針*/
- LINK_NODE *tail; /*排列后有序鏈的表尾指針*/
- LINK_NODE *premin; /*保留鍵值更小的節點的前驅節點的指針*/
- LINK_NODE *min; /*存儲最小節點*/
- LINK_NODE *p; /*當前比較的節點*/
- first = NULL;
- while (head != NULL)
- {
- //在剩余的原鏈表中找出最小值
- for (p = head, min = head; p->next != NULL; p = p->next) {
- if (p->next->data < min->data) {
- premin = p;
- min = p->next;
- }
- }
- //將找出來最小值放到新的鏈表
- if (first == NULL) {
- first = min;
- tail = min;
- } else {
- tail->next = min;
- tail = min;
- }
- //將找出來的最小值從原來的鏈表中脫離
- if (min == head) {
- head = head->next;
- } else {
- premin->next = min->next;
- }
- }
- if (first != NULL) {
- tail->next = NULL;
- }
- head = first;
- return head;
- }
//選擇排序,從小到大。
LINK_NODE *SelectSort(LINK_NODE *head)
{
LINK_NODE *first; /*排列后有序鏈的表頭指針*/
LINK_NODE *tail; /*排列后有序鏈的表尾指針*/
LINK_NODE *premin; /*保留鍵值更小的節點的前驅節點的指針*/
LINK_NODE *min; /*存儲最小節點*/
LINK_NODE *p; /*當前比較的節點*/
first = NULL;
while (head != NULL)
{
//在剩余的原鏈表中找出最小值
for (p = head, min = head; p->next != NULL; p = p->next) {
if (p->next->data < min->data) {
premin = p;
min = p->next;
}
}
//將找出來最小值放到新的鏈表
if (first == NULL) {
first = min;
tail = min;
} else {
tail->next = min;
tail = min;
}
//將找出來的最小值從原來的鏈表中脫離
if (min == head) {
head = head->next;
} else {
premin->next = min->next;
}
}
if (first != NULL) {
tail->next = NULL;
}
head = first;
return head;
}
b、插入排序
直接插入排序的基本思想就是假設鏈表的前面n-1個節點是已經按鍵值排好序的,對於節點n在這個序列中找插入位置,使得n插入后新序列仍然有序。按照這種思想,依次對鏈表從頭到尾執行一遍,就可以使無序鏈表變為有序鏈表。可以通過以下兩個步驟實現
(1)先在原鏈表中以第一個節點為一個有序鏈表,其余節點為待定節點
(2)從原鏈表中依次取結點,插入到有序鏈表的相應位置,使得有序鏈表仍然有序,直至原鏈表的結點全部取完,排序結束。
- //插入排序,從小到大。
- LINK_NODE *InsertSort(LINK_NODE *head)
- {
- LINK_NODE *first; /*為原鏈表剩下用於直接插入排序的節點頭指針*/
- LINK_NODE *t; /*臨時指針變量:插入節點*/
- LINK_NODE *p; /*臨時指針變量*/
- LINK_NODE *q; /*臨時指針變量*/
- first = head->next;
- head->next = NULL;
- while (first != NULL)
- {
- //找到要插入的位置,p是q的前驅。
- for (t = first, q = head; ((q != NULL) && (q->data < t->data)); p = q, q = q->next);
- //無序鏈表中的節點離開,以便它插入到有序鏈表中。
- first = first->next;
- if (q == head) {
- head = t; //插在第一個節點之前
- } else {
- p->next = t;
- }
- t->next = q;
- }
- return head;
- }
//插入排序,從小到大。
LINK_NODE *InsertSort(LINK_NODE *head)
{
LINK_NODE *first; /*為原鏈表剩下用於直接插入排序的節點頭指針*/
LINK_NODE *t; /*臨時指針變量:插入節點*/
LINK_NODE *p; /*臨時指針變量*/
LINK_NODE *q; /*臨時指針變量*/
first = head->next;
head->next = NULL;
while (first != NULL)
{
//找到要插入的位置,p是q的前驅。
for (t = first, q = head; ((q != NULL) && (q->data < t->data)); p = q, q = q->next);
//無序鏈表中的節點離開,以便它插入到有序鏈表中。
first = first->next;
if (q == head) {
head = t; //插在第一個節點之前
} else {
p->next = t;
}
t->next = q;
}
return head;
}
c、冒泡排序
冒泡排序的基本思想就是對當前還未排好序的范圍內的全部節點,自上而下對相鄰的兩個節點依次進行比較和調整,讓鍵值較大的節點往下沉,鍵值較小的往上冒。即:每當兩相鄰的節點比較后發現它們的排序與排序要求相反時,就將它們互換。
- //冒泡排序,從小到大。
- LINK_NODE *BubbleSort(LINK_NODE *head)
- {
- LINK_NODE *endpt; /*控制循環比較*/
- LINK_NODE *p; /*臨時指針變量*/
- LINK_NODE *p1;
- LINK_NODE *p2;
- p1 = (LINK_NODE *)malloc(sizeof(LINK_NODE));
- p1->next = head;
- head = p1;
- for (endpt = NULL; endpt != head; endpt = p) {
- for (p = p1 = head; p1->next->next != endpt; p1 = p1->next) {
- if (p1->next->data > p1->next->next->data) {
- p2 = p1->next->next;
- p1->next->next = p2->next;
- p2->next = p1->next;
- p1->next = p2;
- p = p1->next->next;
- }
- }
- }
- p1 = head;
- head = head->next;
- free(p1);
- p1 = NULL;
- return head;
- }
//冒泡排序,從小到大。
LINK_NODE *BubbleSort(LINK_NODE *head)
{
LINK_NODE *endpt; /*控制循環比較*/
LINK_NODE *p; /*臨時指針變量*/
LINK_NODE *p1;
LINK_NODE *p2;
p1 = (LINK_NODE *)malloc(sizeof(LINK_NODE));
p1->next = head;
head = p1;
for (endpt = NULL; endpt != head; endpt = p) {
for (p = p1 = head; p1->next->next != endpt; p1 = p1->next) {
if (p1->next->data > p1->next->next->data) {
p2 = p1->next->next;
p1->next->next = p2->next;
p2->next = p1->next;
p1->next = p2;
p = p1->next->next;
}
}
}
p1 = head;
head = head->next;
free(p1);
p1 = NULL;
return head;
}
四、單向鏈表運用示例
將鏈表的基本操作統一放在一個文件single_linkedlist.c里面,然后在single_linkedlist.h文件里面聲明,這樣調用起來比較方便。下面貼出各個文件的代碼,方面下次快速使用。
single_linkedlist.c文件代碼
- #include <stdio.h>
- #include <stdlib.h>
- #include "single_linkedlist.h"
- //創建一個結點
- LINK_NODE* create_node(int value)
- {
- LINK_NODE *pLinkNode = NULL;
- pLinkNode = (LINK_NODE *)malloc(sizeof(LINK_NODE));
- pLinkNode->data = value;
- pLinkNode->next = NULL;
- return pLinkNode;
- }
- //使用遞歸的方法,在鏈表的末尾加上一個新的結點
- int _add_node(LINK_NODE** pNode, LINK_NODE* pDataNode)
- {
- if(NULL == *pNode) {
- *pNode = pDataNode;
- return TRUE;
- }
- return _add_node(&(*pNode)->next, pDataNode);
- }
- int add_node(const LINK_NODE** pNode, int value)
- {
- LINK_NODE *pDataNode;
- if(NULL == *pNode) {
- return FALSE;
- }
- pDataNode = create_node(value);
- if(pDataNode == NULL) {
- return FALSE;
- }
- return _add_node((LINK_NODE**)pNode, pDataNode);
- }
- //使用遞歸的方法,刪除數據內容為value的結點
- int _delete_node(LINK_NODE** pNode, int value)
- {
- LINK_NODE* pLinkNode;
- if(NULL == (*pNode)->next) {
- return FALSE;
- }
- pLinkNode = (*pNode)->next;
- if(value == pLinkNode->data) {
- (*pNode)->next = pLinkNode->next;
- free(pLinkNode);
- return TRUE;
- } else {
- return _delete_node(&(*pNode)->next, value);
- }
- }
- int delete_node(LINK_NODE** pNode, int value)
- {
- LINK_NODE* pLinkNode;
- if(NULL == pNode || NULL == *pNode) {
- return FALSE;
- }
- if(value == (*pNode)->data) {
- pLinkNode = *pNode;
- *pNode = pLinkNode->next;
- free(pLinkNode);
- return TRUE;
- }
- return _delete_node(pNode, value);
- }
- //查找結點,返回數據內容為value的結點地址,沒有找到返回NULL.
- LINK_NODE* find_node(const LINK_NODE* pLinkNode, int value)
- {
- if(NULL == pLinkNode)
- return NULL;
- if(value == pLinkNode->data)
- return (LINK_NODE*)pLinkNode;
- return find_node(pLinkNode->next, value);
- }
- //把從pLinkNode結點開始到鏈表結束的結點個數統計出來
- //一般pLinkNode鏈表頭
- int count_list(const LINK_NODE *pLinkNode)
- {
- if(NULL == pLinkNode) {
- return 0;
- }
- return 1 + count_list(pLinkNode->next);
- }
- //把從pLinkNode結點開始到鏈表結束的數據全部打印出來
- //一般pLinkNode為鏈表頭
- void print_list(const LINK_NODE *pLinkNode)
- {
- if(pLinkNode) {
- printf("%d\n", pLinkNode->data);
- print_list(pLinkNode->next);
- }
- }
- //刪除整個鏈表,pNode為鏈表頭。
- void delete_list(LINK_NODE** pNode)
- {
- LINK_NODE** pNext;
- if(NULL == pNode || NULL == *pNode) {
- return ;
- }
- pNext = &(*pNode)->next;
- free(*pNode);
- delete_list(pNext);
- }
- //新建一條鏈表,新的鏈表是原來鏈表的逆轉,使用while循環實現。
- LINK_NODE *reverse_new_loop(LINK_NODE *head)
- {
- LINK_NODE *p1 = NULL, *p2;
- while(head != NULL)
- {
- p2 = (LINK_NODE *) malloc(sizeof(LINK_NODE));
- if(p1 == NULL) {
- p2->next = NULL;
- } else {
- p2->next = p1;
- }
- p1 = p2;
- p2->data = head->data;
- head = head->next;
- }
- return p1;
- }
- //新建一條鏈表,新的鏈表是原來鏈表的逆轉,使用遞歸實現。
- LINK_NODE *reverse_new_recursive(LINK_NODE *head, LINK_NODE *pre)
- {
- LINK_NODE *p = head->next;
- LINK_NODE *new;
- new = (LINK_NODE *) malloc(sizeof(LINK_NODE));
- new->next = pre;
- new->data = head->data;
- if(p) {
- return reverse_new_recursive(p, new);
- } else {
- return new;
- }
- }
- //原地逆轉,使用while循環實現。
- LINK_NODE *reverse_local_loop(LINK_NODE *head)
- {
- LINK_NODE *p;
- LINK_NODE *tmp;
- if(NULL == head) {
- return head;
- }
- p = head->next;
- head->next = NULL;
- while(NULL != p) {
- tmp = p->next;
- p->next = head;
- head = p;
- p = tmp;
- }
- return head;
- }
- //原地逆轉,使用遞歸實現。
- LINK_NODE *reverse_local_recursive(LINK_NODE *head, LINK_NODE *pre)
- {
- LINK_NODE *p = head->next;
- head->next = pre;
- if(p) {
- return reverse_local_recursive(p, head);
- } else {
- return head;
- }
- }
- //選擇排序,從小到大。
- LINK_NODE *SelectSort(LINK_NODE *head)
- {
- LINK_NODE *first; /*排列后有序鏈的表頭指針*/
- LINK_NODE *tail; /*排列后有序鏈的表尾指針*/
- LINK_NODE *premin; /*保留鍵值更小的節點的前驅節點的指針*/
- LINK_NODE *min; /*存儲最小節點*/
- LINK_NODE *p; /*當前比較的節點*/
- first = NULL;
- while (head != NULL)
- {
- //在剩余的原鏈表中找出最小值
- for (p = head, min = head; p->next != NULL; p = p->next) {
- if (p->next->data < min->data) {
- premin = p;
- min = p->next;
- }
- }
- //將找出來最小值放到新的鏈表
- if (first == NULL) {
- first = min;
- tail = min;
- } else {
- tail->next = min;
- tail = min;
- }
- //將找出來的最小值從原來的鏈表中脫離
- if (min == head) {
- head = head->next;
- } else {
- premin->next = min->next;
- }
- }
- if (first != NULL) {
- tail->next = NULL;
- }
- head = first;
- return head;
- }
- //插入排序,從小到大。
- LINK_NODE *InsertSort(LINK_NODE *head)
- {
- LINK_NODE *first; /*為原鏈表剩下用於直接插入排序的節點頭指針*/
- LINK_NODE *t; /*臨時指針變量:插入節點*/
- LINK_NODE *p; /*臨時指針變量*/
- LINK_NODE *q; /*臨時指針變量*/
- first = head->next;
- head->next = NULL;
- while (first != NULL)
- {
- //找到要插入的位置,p是q的前驅。
- for (t = first, q = head; ((q != NULL) && (q->data < t->data)); p = q, q = q->next);
- //無序鏈表中的節點離開,以便它插入到有序鏈表中。
- first = first->next;
- if (q == head) {
- head = t; //插在第一個節點之前
- } else {
- p->next = t;
- }
- t->next = q;
- }
- return head;
- }
- //冒泡排序,從小到大。
- LINK_NODE *BubbleSort(LINK_NODE *head)
- {
- LINK_NODE *endpt; /*控制循環比較*/
- LINK_NODE *p; /*臨時指針變量*/
- LINK_NODE *p1;
- LINK_NODE *p2;
- p1 = (LINK_NODE *)malloc(sizeof(LINK_NODE));
- p1->next = head;
- head = p1;
- for (endpt = NULL; endpt != head; endpt = p) {
- for (p = p1 = head; p1->next->next != endpt; p1 = p1->next) {
- if (p1->next->data > p1->next->next->data) {
- p2 = p1->next->next;
- p1->next->next = p2->next;
- p2->next = p1->next;
- p1->next = p2;
- p = p1->next->next;
- }
- }
- }
- p1 = head;
- head = head->next;
- free(p1);
- p1 = NULL;
- return head;
- }
#include <stdio.h>
#include <stdlib.h>
#include "single_linkedlist.h"
//創建一個結點
LINK_NODE* create_node(int value)
{
LINK_NODE *pLinkNode = NULL;
pLinkNode = (LINK_NODE *)malloc(sizeof(LINK_NODE));
pLinkNode->data = value;
pLinkNode->next = NULL;
return pLinkNode;
}
//使用遞歸的方法,在鏈表的末尾加上一個新的結點
int _add_node(LINK_NODE** pNode, LINK_NODE* pDataNode)
{
if(NULL == *pNode) {
*pNode = pDataNode;
return TRUE;
}
return _add_node(&(*pNode)->next, pDataNode);
}
int add_node(const LINK_NODE** pNode, int value)
{
LINK_NODE *pDataNode;
if(NULL == *pNode) {
return FALSE;
}
pDataNode = create_node(value);
if(pDataNode == NULL) {
return FALSE;
}
return _add_node((LINK_NODE**)pNode, pDataNode);
}
//使用遞歸的方法,刪除數據內容為value的結點
int _delete_node(LINK_NODE** pNode, int value)
{
LINK_NODE* pLinkNode;
if(NULL == (*pNode)->next) {
return FALSE;
}
pLinkNode = (*pNode)->next;
if(value == pLinkNode->data) {
(*pNode)->next = pLinkNode->next;
free(pLinkNode);
return TRUE;
} else {
return _delete_node(&(*pNode)->next, value);
}
}
int delete_node(LINK_NODE** pNode, int value)
{
LINK_NODE* pLinkNode;
if(NULL == pNode || NULL == *pNode) {
return FALSE;
}
if(value == (*pNode)->data) {
pLinkNode = *pNode;
*pNode = pLinkNode->next;
free(pLinkNode);
return TRUE;
}
return _delete_node(pNode, value);
}
//查找結點,返回數據內容為value的結點地址,沒有找到返回NULL.
LINK_NODE* find_node(const LINK_NODE* pLinkNode, int value)
{
if(NULL == pLinkNode)
return NULL;
if(value == pLinkNode->data)
return (LINK_NODE*)pLinkNode;
return find_node(pLinkNode->next, value);
}
//把從pLinkNode結點開始到鏈表結束的結點個數統計出來
//一般pLinkNode鏈表頭
int count_list(const LINK_NODE *pLinkNode)
{
if(NULL == pLinkNode) {
return 0;
}
return 1 + count_list(pLinkNode->next);
}
//把從pLinkNode結點開始到鏈表結束的數據全部打印出來
//一般pLinkNode為鏈表頭
void print_list(const LINK_NODE *pLinkNode)
{
if(pLinkNode) {
printf("%d\n", pLinkNode->data);
print_list(pLinkNode->next);
}
}
//刪除整個鏈表,pNode為鏈表頭。
void delete_list(LINK_NODE** pNode)
{
LINK_NODE** pNext;
if(NULL == pNode || NULL == *pNode) {
return ;
}
pNext = &(*pNode)->next;
free(*pNode);
delete_list(pNext);
}
//新建一條鏈表,新的鏈表是原來鏈表的逆轉,使用while循環實現。
LINK_NODE *reverse_new_loop(LINK_NODE *head)
{
LINK_NODE *p1 = NULL, *p2;
while(head != NULL)
{
p2 = (LINK_NODE *) malloc(sizeof(LINK_NODE));
if(p1 == NULL) {
p2->next = NULL;
} else {
p2->next = p1;
}
p1 = p2;
p2->data = head->data;
head = head->next;
}
return p1;
}
//新建一條鏈表,新的鏈表是原來鏈表的逆轉,使用遞歸實現。
LINK_NODE *reverse_new_recursive(LINK_NODE *head, LINK_NODE *pre)
{
LINK_NODE *p = head->next;
LINK_NODE *new;
new = (LINK_NODE *) malloc(sizeof(LINK_NODE));
new->next = pre;
new->data = head->data;
if(p) {
return reverse_new_recursive(p, new);
} else {
return new;
}
}
//原地逆轉,使用while循環實現。
LINK_NODE *reverse_local_loop(LINK_NODE *head)
{
LINK_NODE *p;
LINK_NODE *tmp;
if(NULL == head) {
return head;
}
p = head->next;
head->next = NULL;
while(NULL != p) {
tmp = p->next;
p->next = head;
head = p;
p = tmp;
}
return head;
}
//原地逆轉,使用遞歸實現。
LINK_NODE *reverse_local_recursive(LINK_NODE *head, LINK_NODE *pre)
{
LINK_NODE *p = head->next;
head->next = pre;
if(p) {
return reverse_local_recursive(p, head);
} else {
return head;
}
}
//選擇排序,從小到大。
LINK_NODE *SelectSort(LINK_NODE *head)
{
LINK_NODE *first; /*排列后有序鏈的表頭指針*/
LINK_NODE *tail; /*排列后有序鏈的表尾指針*/
LINK_NODE *premin; /*保留鍵值更小的節點的前驅節點的指針*/
LINK_NODE *min; /*存儲最小節點*/
LINK_NODE *p; /*當前比較的節點*/
first = NULL;
while (head != NULL)
{
//在剩余的原鏈表中找出最小值
for (p = head, min = head; p->next != NULL; p = p->next) {
if (p->next->data < min->data) {
premin = p;
min = p->next;
}
}
//將找出來最小值放到新的鏈表
if (first == NULL) {
first = min;
tail = min;
} else {
tail->next = min;
tail = min;
}
//將找出來的最小值從原來的鏈表中脫離
if (min == head) {
head = head->next;
} else {
premin->next = min->next;
}
}
if (first != NULL) {
tail->next = NULL;
}
head = first;
return head;
}
//插入排序,從小到大。
LINK_NODE *InsertSort(LINK_NODE *head)
{
LINK_NODE *first; /*為原鏈表剩下用於直接插入排序的節點頭指針*/
LINK_NODE *t; /*臨時指針變量:插入節點*/
LINK_NODE *p; /*臨時指針變量*/
LINK_NODE *q; /*臨時指針變量*/
first = head->next;
head->next = NULL;
while (first != NULL)
{
//找到要插入的位置,p是q的前驅。
for (t = first, q = head; ((q != NULL) && (q->data < t->data)); p = q, q = q->next);
//無序鏈表中的節點離開,以便它插入到有序鏈表中。
first = first->next;
if (q == head) {
head = t; //插在第一個節點之前
} else {
p->next = t;
}
t->next = q;
}
return head;
}
//冒泡排序,從小到大。
LINK_NODE *BubbleSort(LINK_NODE *head)
{
LINK_NODE *endpt; /*控制循環比較*/
LINK_NODE *p; /*臨時指針變量*/
LINK_NODE *p1;
LINK_NODE *p2;
p1 = (LINK_NODE *)malloc(sizeof(LINK_NODE));
p1->next = head;
head = p1;
for (endpt = NULL; endpt != head; endpt = p) {
for (p = p1 = head; p1->next->next != endpt; p1 = p1->next) {
if (p1->next->data > p1->next->next->data) {
p2 = p1->next->next;
p1->next->next = p2->next;
p2->next = p1->next;
p1->next = p2;
p = p1->next->next;
}
}
}
p1 = head;
head = head->next;
free(p1);
p1 = NULL;
return head;
}
single_linkedlist.h文件代碼
- #ifndef _SINGLE_LINKEDLIST_H_
- #define _SINGLE_LINKEDLIST_H_
- #define TRUE 1
- #define FALSE 0
- //定義結點數據結構
- typedef struct _LINK_NODE
- {
- int data;
- struct _LINK_NODE* next;
- }LINK_NODE;
- //創建一個結點
- LINK_NODE* create_node(int value);
- //刪除整個鏈表,pNode為鏈表頭。
- void delete_list(LINK_NODE** pNode);
- //使用遞歸的方法,在鏈表的末尾加上一個新的結點
- int add_node(const LINK_NODE** pNode, int value);
- //使用遞歸的方法,刪除數據內容為value的結點
- int delete_node(LINK_NODE** pNode, int value);
- //查找結點,返回數據內容為value的結點地址,沒有找到返回NULL
- LINK_NODE* find_node(const LINK_NODE* pLinkNode, int value);
- //把從pLinkNode結點開始到鏈表結束的結點個數統計出來
- //一般pLinkNode鏈表頭
- int count_list(const LINK_NODE *pLinkNode);
- //把從pLinkNode結點開始到鏈表結束的數據全部打印出來
- //一般pLinkNode為鏈表頭
- void print_list(const LINK_NODE *pLinkNode);
- //新建一條鏈表,新的鏈表是原來鏈表的逆轉,使用while循環實現。
- LINK_NODE *reverse_new_loop(LINK_NODE *head);
- //新建一條鏈表,新的鏈表是原來鏈表的逆轉,使用遞歸實現。
- LINK_NODE *reverse_new_recursive(LINK_NODE *head, LINK_NODE *pre);
- //原地逆轉,使用while循環實現。
- LINK_NODE *reverse_local_loop(LINK_NODE *head);
- //原地逆轉,使用遞歸實現。
- LINK_NODE *reverse_local_recursive(LINK_NODE *head, LINK_NODE *pre);
- //選擇排序,從小到大。
- LINK_NODE *SelectSort(LINK_NODE *head);
- //插入排序,從小到大。
- LINK_NODE *InsertSort(LINK_NODE *head);
- //冒泡排序,從小到大。
- LINK_NODE *BubbleSort(LINK_NODE *head);
- #endif
#ifndef _SINGLE_LINKEDLIST_H_
#define _SINGLE_LINKEDLIST_H_
#define TRUE 1
#define FALSE 0
//定義結點數據結構
typedef struct _LINK_NODE
{
int data;
struct _LINK_NODE* next;
}LINK_NODE;
//創建一個結點
LINK_NODE* create_node(int value);
//刪除整個鏈表,pNode為鏈表頭。
void delete_list(LINK_NODE** pNode);
//使用遞歸的方法,在鏈表的末尾加上一個新的結點
int add_node(const LINK_NODE** pNode, int value);
//使用遞歸的方法,刪除數據內容為value的結點
int delete_node(LINK_NODE** pNode, int value);
//查找結點,返回數據內容為value的結點地址,沒有找到返回NULL
LINK_NODE* find_node(const LINK_NODE* pLinkNode, int value);
//把從pLinkNode結點開始到鏈表結束的結點個數統計出來
//一般pLinkNode鏈表頭
int count_list(const LINK_NODE *pLinkNode);
//把從pLinkNode結點開始到鏈表結束的數據全部打印出來
//一般pLinkNode為鏈表頭
void print_list(const LINK_NODE *pLinkNode);
//新建一條鏈表,新的鏈表是原來鏈表的逆轉,使用while循環實現。
LINK_NODE *reverse_new_loop(LINK_NODE *head);
//新建一條鏈表,新的鏈表是原來鏈表的逆轉,使用遞歸實現。
LINK_NODE *reverse_new_recursive(LINK_NODE *head, LINK_NODE *pre);
//原地逆轉,使用while循環實現。
LINK_NODE *reverse_local_loop(LINK_NODE *head);
//原地逆轉,使用遞歸實現。
LINK_NODE *reverse_local_recursive(LINK_NODE *head, LINK_NODE *pre);
//選擇排序,從小到大。
LINK_NODE *SelectSort(LINK_NODE *head);
//插入排序,從小到大。
LINK_NODE *InsertSort(LINK_NODE *head);
//冒泡排序,從小到大。
LINK_NODE *BubbleSort(LINK_NODE *head);
#endif
main.c文件代碼
- #include <stdio.h>
- #include <stdlib.h>
- #include "single_linkedlist.h"
- int main(int argc, charchar **argv)
- {
- LINK_NODE *head;
- LINK_NODE *reverse1, *reverse2;
- head = create_node(1);
- add_node((const LINK_NODE **)&head, 5);
- add_node((const LINK_NODE **)&head, 2);
- add_node((const LINK_NODE **)&head, 4);
- add_node((const LINK_NODE **)&head, 3);
- printf("=======原始鏈表head\n");
- print_list(head);
- //逆轉生成一個新的鏈表,循環實現
- reverse1 = reverse_new_loop(head);
- printf("=======head逆轉成的鏈表reverse1\n");
- print_list(reverse1);
- //逆轉生成一個新的鏈表,遞歸實現
- reverse2 = reverse_new_recursive(head, NULL);
- printf("=======head逆轉成的鏈表reverse2\n");
- print_list(reverse2);
- //本地逆轉,循環實現
- reverse1 = reverse_local_loop(reverse1);
- printf("=======reverse1本地逆轉成的鏈表reverse1\n");
- print_list(reverse1);
- //本地逆轉,遞歸實現
- reverse2 = reverse_local_loop(reverse2);
- printf("=======reverse2本地逆轉成的鏈表reverse2\n");
- print_list(reverse2);
- //選擇排序
- head = SelectSort(head);
- printf("=======head選擇排序后的鏈表\n");
- print_list(head);
- //插入排序
- reverse1 = InsertSort(reverse1);
- printf("=======reverse1插入排序后的鏈表\n");
- print_list(reverse1);
- //冒泡排序
- reverse2 = BubbleSort(reverse2);
- printf("=======reverse2冒泡排序后的鏈表\n");
- print_list(reverse2);
- delete_list(&head);
- delete_list(&reverse1);
- delete_list(&reverse2);
- return 0;
- }
#include <stdio.h>
#include <stdlib.h>
#include "single_linkedlist.h"
int main(int argc, char **argv)
{
LINK_NODE *head;
LINK_NODE *reverse1, *reverse2;
head = create_node(1);
add_node((const LINK_NODE **)&head, 5);
add_node((const LINK_NODE **)&head, 2);
add_node((const LINK_NODE **)&head, 4);
add_node((const LINK_NODE **)&head, 3);
printf("=======原始鏈表head\n");
print_list(head);
//逆轉生成一個新的鏈表,循環實現
reverse1 = reverse_new_loop(head);
printf("=======head逆轉成的鏈表reverse1\n");
print_list(reverse1);
//逆轉生成一個新的鏈表,遞歸實現
reverse2 = reverse_new_recursive(head, NULL);
printf("=======head逆轉成的鏈表reverse2\n");
print_list(reverse2);
//本地逆轉,循環實現
reverse1 = reverse_local_loop(reverse1);
printf("=======reverse1本地逆轉成的鏈表reverse1\n");
print_list(reverse1);
//本地逆轉,遞歸實現
reverse2 = reverse_local_loop(reverse2);
printf("=======reverse2本地逆轉成的鏈表reverse2\n");
print_list(reverse2);
//選擇排序
head = SelectSort(head);
printf("=======head選擇排序后的鏈表\n");
print_list(head);
//插入排序
reverse1 = InsertSort(reverse1);
printf("=======reverse1插入排序后的鏈表\n");
print_list(reverse1);
//冒泡排序
reverse2 = BubbleSort(reverse2);
printf("=======reverse2冒泡排序后的鏈表\n");
print_list(reverse2);
delete_list(&head);
delete_list(&reverse1);
delete_list(&reverse2);
return 0;
}
Makefile文件代碼
- CC = gcc
- WORKDIR =
- INCLUDES =
- LIBS =
- LINKS =
- TARGET = main
- src=$(wildcard *.c ./callback/*.c)
- C_OBJS=$(patsubst %.c, %.o,$(src))
- #C_OBJS=$(dir:%.c=%.o)
- compile:$(TARGET)
- $(C_OBJS):%.o:%.c
- $(CC) $(CFLAGS) $(INCLUDES) -o $*.o -c $*.c
- $(TARGET):$(C_OBJS)
- $(CC) -o $(TARGET) $^ $(LIBS) $(LINKS)
- @echo
- @echo Project has been successfully compiled.
- @echo
- install: $(TARGET)
- cp $(TARGET) $(INSTALL_PATH)
- uninstall:
- rm -f $(INSTALL_PATH)/$(TARGET)
- rebuild: clean compile
- clean:
- rm -rf *.o $(TARGET) *.log *~
