Table of Contents
定義
相對於順序表而言,“勤拿少取”這是對鏈表最形象的描述。意指,它需要一個結點,就在內存中分配一塊內存單元。比順序表不足的是,鏈表的每個結點中,需要一個存儲單元保存指向下一個結點的地址。
鏈表的訪問需要從第一個結點(或稱頭結點)開始尋找,(順序表可以根據下標直接訪問)。鏈表的插入和刪除只需對指定位置的結點操作即可。
常見的鏈表,根據指向下個鏈表的指針可分爲單向鏈表,雙向鏈表。根據第一個結點是否存儲元素可分爲帶頭結點的鏈表和不帶頭結點的鏈表。再根據末尾結點next指針的指向可分爲循環鏈表和非循環鏈表。
*下面程序以單向帶頭結點的非循環鏈表爲例。
實現
定義結構
typedef int LinkType; //存儲單元類型
typedef struct linkNode {
LinkType key; //結點的key值
struct linkNode *next; //指向下一個結點
} LNode, *LinkList;//LNode 是普通類型,LinkList是指針類型
定義LinkType類型,使該鏈表結構適合更多數據類型。每個鏈表的結點,包含一個值域key和一個指針域next。這裏聲明兩種類型LNode和LinkList。以下兩行代碼是等價的。
LNode* node = (LNode*)malloc(sizeof(LNode));
LinkList node = (LinkList)malloc(sizeof(LNode));
定義操作
創建頭結點
/**
* 創建頭結點
*/
LinkList createHead_link() {
LinkList head = (LinkList) malloc(sizeof(LNode));
head->next = NULL;
return head;
}
這裏是動態分配一個內存單元存儲頭結點,也可以參照順序表中,使用LNode head,由系統分配內存。
插入結點
/**
* 頭插法
*/
void insertFirst_link(LinkList head, LinkType val) {
LinkList node = (LinkList) malloc(sizeof(LNode));
node->key = val;
node->next = head->next;
head->next = node;
}
在帶頭結點的鏈表中,頭插法表示每次將結點插入到頭結點的後面。在不帶頭結點的鏈表中,將待插入的結點放在鏈表中第一個結點的前面,代替之成爲第一個結點。
/**
* 尾插法
*/
void insertLast_link(LinkList head, LinkType val) {
LinkList temp = head;
while (temp->next != NULL) //找到末尾結點
temp = temp->next;
LinkList node = (LinkList) malloc(sizeof(LNode));
node->key = val;
temp->next = node;
node->next = NULL;
}
對於尾插法而言,不區分帶頭結點和不帶頭結點的鏈表。只將待插入的結點插到鏈表的最後一個位置。因此需要先循環到鏈表的末尾。
/**
* 指定位置插入,position表示插入後的位置,0表示頭結點後的第一個結點
*/
void insert_link(LinkList head, int position, LinkType val) {
if (position < 0) //-1 從末尾添加,採用尾插法
insertLast_link(head, val);
else if (position == 0) //從第一個結點插入,採用頭插法
insertFirst_link(head, val);
else { //
LinkList temp = head->next;
while (temp != NULL && --position > 0) { //找到合適的位置結點
temp = temp->next;
}
LinkList node = (LinkList) malloc(sizeof(LNode));
node->key = val;
node->next = temp->next;
temp->next = node;
}
}
先根據下標找到待插入的位置,然後插入結點。對比順序表,先移動指定位置的後續結點,再插入新的結點。
刪除結點
/**
* 刪除節點(指定位置),下標從0開始
*/
void removeNode_link(LinkList head, int index, LinkType &key) {
if (index < 0) {
printf("指定下標值不正確\n");
return;
}
LinkList node = head;
int i = 0;
while (!node->next || i < index) { //尋找指定下標的節點,結束循環時,i==index
node = node->next;
i++;
}
if (i == index) { //找到指定節點
LinkList temp = node->next; //temp 是要被刪除的節點
node->next = temp->next;
temp->next = NULL;
key = temp->key;
free(temp);
} else { //沒找到
printf("沒找到指定下標的值");
}
}
下標從0開始,表示頭結點後的第一個結點。先找到待刪除的結點,取出key值,再刪除該結點。
/**
* 刪除節點(指定節點)
*/
void removeNode_link(LinkList head, LinkType val) {
LinkList node = head;
while (!node->next) {
if (node->next->key == val)
break;
node = node->next;
}
if (node->next != NULL) { //找到要刪除的節點
LinkList temp = node->next; //temp 是要被刪除的節點
node->next = temp->next;
temp->next = NULL;
free(temp);
} else {
printf("沒找到要刪除的節點\n");
}
}
首先根據val值,找到待刪除的結點,最後刪除之。
銷燬鏈表
/**
* 銷燬鏈表
*/
void destory_link(LinkList head) {
while (head->next != NULL) {
LinkList node = head->next;
head->next = node->next;
free(node);
}
}
釋放掉除頭結點之外的所有結點佔用的內存。
最後附上,頭文件的定義
/*
* linklist.h
* 順序表的鏈式存儲結構
* Created on: 2016年8月30日
* Author: flueky
*/
#ifndef LINKLIST_H_
#define LINKLIST_H_
typedef int LinkType; //存儲單元類型
typedef struct linkNode {
LinkType key; //節點的key值
struct linkNode *next; //指向下一個節點
} LNode, *LinkList;//LNode 是普通類型,LinkList是指針類型
/**
* 創建頭結點
*/
LinkList createHead_link();
/**
* 頭插法
*/
void insertFirst_link(LinkList, LinkType);
/**
* 尾插法
*/
void insertLast_link(LinkList, LinkType);
/**
* 在指定位置插入
*/
void insert_link(LinkList,int, LinkType);
/**
* 刪除節點(指定位置)
*/
void removeNode_link(LinkList,int,LinkType&);
/**
* 刪除節點(指定節點)
*/
void removeNode_link(LinkList,LinkType);
/**
* 銷燬鏈表
*/
void destory_link(LinkList);
#endif /* LINKLIST_H_ */