/*************************************************************************
> File Name: link_list.c
> Author: Andy001847
> Mail: [email protected]
> Created Time: 2014年10月25日 星期六 11時51分34秒
************************************************************************/
//雙向鏈表的實現
#include <stdio.h>
#include <stdlib.h>
//定義雙向鏈表中的節點
typedef struct node{
int data; //節點的數據域
struct node *p_next;//下一個節點的位置
struct node *p_pre;//前一個結點的位置
}Node;
static Node head, tail; //虛構頭尾節點
//初始化鏈表
void init(){
head.p_next = &tail;//將尾節點“掛”在頭節點後面
tail.p_pre = &head;//將頭節點“掛”在尾節點前面
}
//清空鏈表
void deinit(){
while (head.p_next != &tail){
Node *p_node = head.p_next;//將節點“掛”在頭節點後面,形成第一個有效數據元素
head.p_next = head.p_next->p_next;//刪除第一個有效節點
p_node->p_next->p_pre = &head;//將刪除後的第一個有效節點和頭節點相連
free(p_node); //釋放已經刪除的節點空間
p_node = NULL;//防止釋放後的野指針
}
}
//從鏈表頭部插入節點
void insert_head(int num){
Node *p_node = (Node *)malloc(sizeof(Node));//動態分配內存一個新節點
if (!p_node){ //處理動態內存分配失敗的情況
perror("malloc1");
return;
}
p_node->data = num;//將值賦給新節點
head.p_next->p_pre = p_node;//將新節點“掛”頭節點後面
p_node->p_next = head.p_next;//是新節點成爲鏈表的一個節點
p_node->p_pre = &head;//使頭節點和新節點項鍊
head.p_next = p_node;
}
//從尾部插入新節點
void append(int num){
Node *p_node = (Node *)malloc(sizeof(Node));//動態分配一個內存給新節點
if (!p_node){
perror("malloc2");
return;
}
p_node->data = num;//將值賦給新節點;
tail.p_pre->p_next = p_node;//將新節點“掛”在尾部的第一個有效節點上
p_node->p_pre = tail.p_pre;//使新節點和尾節點相連
p_node->p_next = &tail;//將新節點“掛”在尾部
tail.p_pre = p_node;
}
//按順序插入新節點
void insert_order(int num){
Node *n_node = (Node *)malloc(sizeof(Node));//爲新節點動態分配內存
if (!n_node){ //處理動態內存分配失敗的情況
perror("malloc3");
return;
}
Node *p_node = NULL;
for (p_node = &head; p_node != &tail; p_node = p_node->p_next){
Node *p_tmp = p_node->p_next;
if ((p_tmp->data) > num || p_tmp == &tail){//插入新節點的情況
n_node->data = num;//將值賦給新節點
n_node->p_pre = p_tmp->p_pre;//將新節點“掛”在指定位置中
p_tmp->p_pre->p_next = n_node;
n_node->p_next = p_tmp;
p_tmp->p_pre = n_node;
break;
}
}
}
//指定插入某節點後面(如果有多個值相同,插入第一個後面)
void insert(int base, int num){
Node *n_node = (Node *)malloc(sizeof(Node));
if (!n_node){ //處理動態內存分配失敗的情況
perror("malloc4");
return;
}
Node *p_node = NULL;
for (p_node = &head; p_node != &tail; p_node = p_node->p_next){
Node *p_tmp = p_node->p_next;
if ((p_tmp->data) == base){//找到基準位置
n_node->data = num;//將值賦給新節點
n_node->p_next = p_tmp->p_next;//將新節點“掛”在基準點後面
p_tmp->p_next->p_pre = n_node;//使新節點和基準點相連接
n_node->p_pre = p_tmp;
p_tmp->p_next = n_node;
return;
}
}
//處理基準點不存在的情況
printf("值爲%d的節點不存在!無法將值爲值%d的節點插入其後。\n", base, num);
free(n_node);
n_node = NULL;
}
//刪除第一個有效節點
void delete_head(){
if (head.p_next != &tail){
Node *p_node = head.p_next;
head.p_next = head.p_next->p_next;//將第一個有效節點刪除
p_node->p_next->p_pre = &head;//使刪除後的節點相連
free(p_node);
p_node = NULL;
}
}
//刪除最後一個有效節點
void delete_tail(){
if (tail.p_pre != &head){
Node *p_node = tail.p_pre;
tail.p_pre = tail.p_pre->p_pre;//將最後一個有效節點刪除
p_node->p_pre->p_next = &tail;//使刪除後的節點相連
free(p_node); //釋放刪除後的節點空間
p_node = NULL;
}
}
//刪除指定節點
void delete(int num){
Node *p_node = NULL;
for (p_node = &head; p_node != &tail; p_node = p_node->p_next){
Node *p_tmp = p_node->p_next;
if (p_tmp != &tail && (p_tmp->data) == num){//找到要刪除的節點位置
p_node->p_next = p_tmp->p_next;//刪除指定的節點
p_tmp->p_next->p_pre = p_node;//使刪除後的節點相連
free(p_tmp); //刪除釋放後的節點空間
p_tmp = NULL;
break;
}
}
}
//獲取鏈表節點個數
int size(){
int cnt = 0;
Node *p_node = NULL;
//方法一
for (p_node = &head; p_node != &tail; p_node = p_node->p_next){
Node *p_tmp = p_node->p_next;
if (p_tmp != &tail){//判斷有效節點的最終位置
cnt++;
}
}
return cnt;
//方法二
/*
for(p_node = &tail; p_node != &head; p_node = p_node -> p_pre){
Node *p_tmp = p_node -> p_pre;
if(p_tmp != &head){
cnt++;
}
}
return cnt;
*/
}
//獲取頭部節點數據
int first(){
return head.p_next == &tail ? 0 : head.p_next->data;
}
//獲取尾部節點數據
int last(){
return tail.p_pre == &head ? 0 : tail.p_pre->data;
}
//順序打印鏈表數據
void print_order(){
Node *p_node = NULL;
for (p_node = &head; p_node != &tail; p_node = p_node->p_next){//從頭部開始打印節點數據
Node *p_tmp = p_node->p_next;
if (p_tmp != &tail){
printf("%d ", p_tmp->data);
}
}
printf("\n");
}
//逆序打印鏈表數據
void print_invert(){
Node *p_node = NULL;
for (p_node = &tail; p_node != &head; p_node = p_node->p_pre){//從尾部開始打印節點數據
Node *p_tmp = p_node->p_pre;
if (p_tmp != &head){
printf("%d ", p_tmp->data);
}
}
printf("\n");
}
//讀取整數函數
int readInt(){
int value = 0;
while (!scanf("%d", &value)){
scanf("%*[^\n]");//清除緩衝區中的非法換行符
scanf("%*c"); //清除緩衝區中的非法字符
printf("輸入有誤!請重新輸入:");//如果不合法輸入,給出提示
}
scanf("%*[^\n]");
scanf("%*c");
return value;
}
int main(void){
init(); //初始化鏈表
char choice = 'y';//該變量用於讓用戶選擇是否繼續操作鏈表
int tmp = 0; //設置臨時變量,用於選擇對於鏈表的操作方式
do{
int num = 0;
printf("請輸入一個整數:");//提示輸入
num = readInt();
printf("請選擇插入的方式,0從頭部插入,1從尾部插入,2指定數字後面插入:");//選擇操作鏈表方式
tmp = readInt();//調用readInt函數,讀取臨時變量的值,從而選定鏈表操作方式
int base = 0;
switch (tmp){
case 0:
insert_head(num);//在頭部插入數據
break;
case 1:
append(num); //在尾部插入數據
break;
case 2:
printf("請輸入指定數字:");
base = readInt();
insert(base, num);//指定位置插入數據,其中base爲鏈表中的基準點,num是要插入在base後面的新節點
break;
default: //錯誤處理
printf("無此種方式!\n");
break;
}
printf("是否繼續?輸入y繼續,否則停止:");//提示是否繼續操作鏈表
scanf("%c", &choice);
} while (choice == 'y' || choice == 'Y');//循環條件
printf("有效元素個數%d\n", size());//檢查輸入的元素個數
printf("首元素:%d,尾元素:%d\n", first(), last());//查看頭尾節點
tmp = 0;
printf("請選擇輸出方式,0代表順序輸出鏈表數據,1代表逆序輸出鏈表數據:");//提示選擇雙向鏈表的打印方式
tmp = readInt();//調用readInt函數,從而選定輸出方式
switch (tmp){
case 0:
print_order();//順序輸出鏈表元素
break;
case 1:
print_invert();//逆序輸出鏈表元素
break;
default: //錯誤處理
printf("無此種方式!\n");
break;
}
printf("是否要刪除節點?輸入y刪除,否則不刪除:");//選擇是否對鏈表進行刪除操作
scanf("%c", &choice);//讀入用戶選擇
if (choice == 'y' || choice == 'Y'){//如果選擇刪除,則進行下面操作
char ch = 'y';
do{
printf("請選擇刪除方式,0代表從頭部刪除,1代表從尾部刪除,2代表指定數字刪除:");//選擇刪除方式
tmp = readInt();//讀取用戶選擇
int num = 0;
switch (tmp){
case 0:
delete_head();//從頭部刪除
break;
case 1:
delete_tail();//從尾部刪除
break;
case 2:
printf("請輸入要刪除的數:");
num = readInt();
delete(num); //指定位置刪除
break;
default: //錯誤處理
printf("無此種方式!\n");
break;
}
printf("是否繼續刪除?輸入y繼續,否則停止:");//讓用戶選擇是否繼續操作鏈表
scanf("%c", &ch);//讀取用戶選擇
} while (ch == 'y' || ch == 'Y');
}
printf("請選擇輸出方式,0代表順序輸出鏈表數據,1代表逆序輸出鏈表數據:");//再次選擇輸出鏈表數據
tmp = readInt();//讀取用戶選擇
switch (tmp){
case 0:
print_order();//順序輸出鏈表數據
break;
case 1:
print_invert();//逆序輸出鏈表數據
break;
default: //錯誤處理
printf("無此種方式!\n");
break;
}
deinit(); //清空鏈表
return 0;
}
運行結果演示: