數據結構入門-離散存儲(鏈表)


一、預備知識:typedef

基本使用

#include <stdio.h>

typedef int AAA; // 為int再重新取一個名字,AAA就等於int

typedef struct Student
{
	int sid;
	char name[100];
	char sex;
}ST;

int main(void)
{

	int i = 10; // 等價於 AAA = 10; 

	struct Student st;  // 等價於  ST st;
	struct Student * ps = &st;  // 等價於 ST * ps = &st;


	ST st2;
	st2.sid = 10;

	printf("%d \n", st2.sid);

	return 0;
}

也可以這樣使用,這樣更加的方便

#include <stdio.h>


typedef struct Student
{
	int sid;
	char name[100];
	char sex;
}* PST;  // PST等價於 typedef struct * 

int main(void)
{
	struct Student st;
	PST ps = &st;

	ps->sid = 99;
	printf("%d\n", ps->sid);

	return 0;
}

還可以把上面的兩個結合起來

#include <stdio.h>


typedef struct Student
{
	int sid;
	char name[100];
	char sex;
}* PST , STU;  // PST等價於 typedef struct *  , STU代表了typedef struct

int main(void)
{
	STU st;  // 等價於struct Student st
	PST ps = &st;

	ps->sid = 99;
	printf("%d\n", ps->sid);

	return 0;
}

二、離散存儲(鏈表)

定義:n個節點離散分配,彼此通過指針相連,每一個節點只有一個前驅節點和一個后續節點,首節點沒有前驅節點,尾節點沒有后續節點

專業術語:

  1. 首節點:第一個有效節點
  2. 尾節點:最后一個有效節點
  3. 頭節點:首節點前面
  4. 頭指針:指向頭節點的指針變量
  5. 尾指針:指向尾節點的指針變量

注意:頭節點的數據類型和首節點類型一樣,頭節點里面沒有存放有效數據,沒有實際含義,為了方便對鏈表的操作

如果通過希望一個函數來對鏈表進行處理,我們至少需要接收鏈表的那些參數

只需要一個參數:頭指針

因為我們可以通過頭指針推算出鏈表的其他所有參數

每一個鏈表節點的數據類型如何表示

#include <stdio.h>

typedef struct Node
{
	int data;  // 數據域
	struct Node * pNext; // 指針域 指向了和它本身類型一樣的另外一個節點
}NODE , *PNODE;
// NODE 等價於struct Node
// PNODE 等價於struct Node *

int main(void)
{
	return 0;
}

分類:

  1. 單鏈表
  2. 雙鏈表:每一個節點有兩個指針域
  3. 循環鏈表:能通任何一個節點找到其他所有的節點
  4. 非循環鏈表

算法:

  1. 遍歷
  2. 查找
  3. 清空
  4. 銷毀
  5. 求長度
  6. 排序
  7. 刪除節點
  8. 插入節點

算法

狹義的算法是與數據的存儲方式密切相關

廣義的算法與數據的存儲方式無關

泛型

利用某種技術達到的效果就是:不同的存儲方式,執行的操作是一樣的

多敲代碼,熟練的掌握,並進行改進

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



typedef struct Node
{
	int data;
	struct Node * pNext;
}NODE , *PNODE;   // NODE等價於struct Node , PNODE等價於struct Node *


PNODE create_list(void);
void traverse_list(PNODE pHead);
bool is_empty(PNODE pHead);
int length_list(PNODE pHead);
bool insert_list(PNODE , int ,int); // 第二個是插入位置,第三個是插入的值
bool delete(PNODE , int, int*); // 第二個是刪除的位置,第三個是所刪除位置的值
void sort_list(PNODE pHead);



int main(void)
{
	PNODE pHead = NULL; // 等價於struct Node * pHead = NULL;

	pHead = create_list(); // 創建一個非循環單鏈表,並將該鏈表的頭節點地址付給pHead

	// if(is_empty(pHead))
	// 	printf("鏈表為空\n");
	// else
	// 	printf("鏈表不為空\n");

	// printf("鏈表的長度為%d\n", length_list(pHead) );
	// sort_list(pHead);
	insert_list(pHead , 4, 99);

	int val;
	if(delete(pHead, 1 , &val))
	{
		printf("刪除成功,你刪除的是%d\n", val);
	}
	else
	{
		printf("刪除失敗\n");
	}
	
	traverse_list(pHead);


	return 0;
}


// 構建一個鏈表,並把頭節點地址值返回
PNODE create_list(void)
{
	int len;
	int i;
	int val; // 用來臨時存放用戶輸入的節點的值

	// 分配了一個不存放數據的頭結點
	PNODE pHead = (PNODE)malloc(sizeof(NODE));
	if (pHead == NULL)
	{
		printf("分配失敗,程序終止!\n");
		exit(-1);
	}

	// pTail始終執行的都是尾結點
	PNODE pTail = pHead;
	pTail->pNext = NULL;


	printf("請輸入你需要生成的鏈表節點的個數:\n");
	scanf("%d" , &len);

	for (i = 0; i < len; ++i)
	{
		printf("請輸入第%d個節點的值:", i+1);
		scanf("%d" , &val);

		PNODE pNew = (PNODE)malloc(sizeof(NODE));
		if (pNew == NULL)
		{
			printf("分配失敗,程序終止!\n");
			exit(-1);
		}

		pNew->data = val;
		pTail->pNext = pNew;
		pNew->pNext = NULL;
		pTail = pNew;
	}

	return pHead;
}

// 進行遍歷
void traverse_list(PNODE pHead)
{
	// 自定義一個指針用於遍歷
	PNODE p = pHead->pNext;
	while(p != NULL){
		printf("%d ",p->data );
		p = p->pNext;
	}
	return;
}


// 判斷鏈表是否為空
bool is_empty(PNODE pHead)
{
	if (pHead->pNext == NULL)
		return true;
	else
		return false;
}

// 鏈表的長度
int length_list(PNODE pHead)
{
	// 自定義一個指針用於計算鏈表的長度
	PNODE p = pHead->pNext;
	int len = 0;

	while(NULL != p)
	{
		++len;
		p = p->pNext;
	}
	return len;
}

// 進行排序
void sort_list(PNODE pHead)
{
	// 這里和數組的排序差不多,思想是一樣的


	int i , j , t;
	PNODE p , q;

	int len = length_list(pHead);

	for (i = 0 , p = pHead->pNext; i < len -1; ++i , p = p->pNext)
	{
		for (j = i+1 , q = p->pNext; j < len; ++j , q = q->pNext)
		{
			if (p->data > q->data)
			{
				t = p->data;
				p->data = q->data;
				q->data = t;
			}
		}
	}

	return;

}



// 插入操作
// 在pHead所指向鏈表的第pos個節點的前面插入一個新的結點,該結點的值是val,pos從1開始
bool insert_list(PNODE pHead, int pos , int val)
{

	int i = 0;
	PNODE p = pHead;

	while(NULL != p && i < pos-1)
	{
		p = p->pNext;
		++i;
	}

	if (i > pos-1 || NULL == p)
		return false;


	PNODE pNew = (PNODE)malloc(sizeof(NODE));
	if (NULL == pNew)
	{
		printf("動態分配內存失敗\n");
		exit(-1);
	}
	pNew->data = val;
	PNODE q = p->pNext;
	p->pNext = pNew;
	pNew->pNext = q;

	return true;
}

// 刪除操作
bool delete(PNODE pHead , int pos, int * pval)
{

	int i = 0;
	PNODE p = pHead;

	while(NULL != p->pNext && i < pos-1)
	{
		p = p->pNext;
		++i;
	}

	if (i > pos-1 || NULL == p->pNext)
		return false;



	PNODE q = p->pNext;
	*pval = q->data;

	// 刪除p結點后面的結點
	p->pNext = p->pNext->pNext;
	free(q);
	q = NULL;

	return true;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM